CORS error in Typescript Express.js API, when request from client (different server)

Viewed 692

I'm converting an Express.js API to Typescript, that has a client server react-scripts counterpart. The Express.js API is reachable under port 5000 and the client via port 3000. To handle requests between the two servers, the project uses the cors package (https://www.npmjs.com/package/cors) as a middleware.

When I run my to JavaScript compiled files, the requests from the client are blocked by the CORS policy of my browser.

Access to fetch at 'http://localhost:5000/prs?username=mygithubuser' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

When I run the old code (pre-Typescript conversion, aka original JavaScript files), it works without problems. There are not many changes to the code (in api/index.ts), so I am clueless why it blocks the request.

This is the old api/index.js (working)

'use strict';

const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const dotenv = require('dotenv');
const setupGithubApi = require('./setupHelpers/setupGithubApi');
const setupGitlabApi = require('./setupHelpers/setupGitlabApi');
const setupErrorHandling = require('./setupHelpers/setupErrorHandling');
const PrController = require('./controllers/pr');
const path = require('path');
const compression = require('compression');

const start = () => {
  // Load environment variables from .env file
  dotenv.config();

  const app = express();

  const shouldCompress = (req, res) => {
    if (req.headers['x-no-compression']) {
      return false;
    }
    return compression.filter(req, res);
  };

  const githubApi = setupGithubApi();
  const gitlabApi = setupGitlabApi();

  const port = process.env.PORT || 5000;

  app.set('port', port);
  app.set('github', githubApi);
  app.set('gitlab', gitlabApi);

  setupErrorHandling(app);

  app.use(express.static(path.join(__dirname, '../build')));

  app.use(bodyParser.json());

  const corsOptions = {
    origin: process.env.REACT_APP_HOSTNAME,
  };

  app.use(cors(corsOptions));

  app.use(
    compression({
      filter: shouldCompress,
    })
  );

  app.get('/prs', PrController.index);

  app.get('/*', (req, res) => {
    res.sendFile(path.join(__dirname, '../build', 'index.html'));
  });

  app.listen(port, () => {
    console.log(`Express server listening on port ${port}`);
  });
};

module.exports = start;

This is the Typescript version, api/index.ts (returning cors error)

import express from 'express';
import bodyParser from 'body-parser';
import cors from 'cors';
import dotenv from 'dotenv';
import path from 'path';
import compression from 'compression';
import setupGithubApi from './setupHelpers/setupGithubApi';
import setupGitlabApi from './setupHelpers/setupGitlabApi';
import setupErrorHandling from './setupHelpers/setupErrorHandling';
import PrController from './controllers/pr';

const start = () => {
  // Load environment variables from .env file
  dotenv.config();

  const app = express();

  const shouldCompress: compression.CompressionFilter = (req, res) => {
    if (req.headers['x-no-compression']) {
      return false;
    }
    return compression.filter(req, res);
  };

  const githubApi = setupGithubApi();
  const gitlabApi = setupGitlabApi();

  const port = process.env.PORT || 5000;

  app.set('port', port);
  app.set('github', githubApi);
  app.set('gitlab', gitlabApi);

  setupErrorHandling(app);

  app.use(express.static(path.join(__dirname, '../../build')));

  app.use(bodyParser.json());

  const corsOptions = {
    origin: [process.env.REACT_APP_HOSTNAME],
  };

  app.use(cors(corsOptions));
  app.options('*', cors(corsOptions));

  app.use(
    compression({
      filter: shouldCompress,
    })
  );

  app.get('/prs', PrController.index);

  app.get('/*', (req, res) => {
    res.sendFile(path.join(__dirname, '../../build', 'index.html'));
  });

  app.listen(port, () => {
    console.log(`Express server listening on port ${port}`);
  });
};

module.exports = start;

When compiled into api/build/index.js (returning cors error)

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const body_parser_1 = __importDefault(require("body-parser"));
const cors_1 = __importDefault(require("cors"));
const dotenv_1 = __importDefault(require("dotenv"));
const path_1 = __importDefault(require("path"));
const compression_1 = __importDefault(require("compression"));
const setupGithubApi_1 = __importDefault(require("./setupHelpers/setupGithubApi"));
const setupGitlabApi_1 = __importDefault(require("./setupHelpers/setupGitlabApi"));
const setupErrorHandling_1 = __importDefault(require("./setupHelpers/setupErrorHandling"));
const pr_1 = __importDefault(require("./controllers/pr"));
const start = () => {
    // Load environment variables from .env file
    dotenv_1.default.config();
    const app = (0, express_1.default)();
    const shouldCompress = (req, res) => {
        if (req.headers['x-no-compression']) {
            return false;
        }
        return compression_1.default.filter(req, res);
    };
    const githubApi = (0, setupGithubApi_1.default)();
    const gitlabApi = (0, setupGitlabApi_1.default)();
    const port = process.env.PORT || 5000;
    app.set('port', port);
    app.set('github', githubApi);
    app.set('gitlab', gitlabApi);
    (0, setupErrorHandling_1.default)(app);
    app.use(express_1.default.static(path_1.default.join(__dirname, '../../build')));
    app.use(body_parser_1.default.json());
    const corsOptions = {
        origin: [process.env.REACT_APP_HOSTNAME],
    };
    app.use((0, cors_1.default)(corsOptions));
    app.options('*', (0, cors_1.default)(corsOptions));
    app.use((0, compression_1.default)({
        filter: shouldCompress,
    }));
    app.get('/prs', pr_1.default.index);
    app.get('/*', (req, res) => {
        res.sendFile(path_1.default.join(__dirname, '../../build', 'index.html'));
    });
    app.listen(port, () => {
        console.log(`Express server listening on port ${port}`);
    });
};
module.exports = start;

This is the tsconfig.json

{
    "compilerOptions": {
        "module": "commonjs",
        "esModuleInterop": true,
        "target": "es6",
        "moduleResolution": "node",
        "noUnusedLocals": false,
        "outDir": "./build"
    },
    "include": [
        "./**/*.ts"
    ]
}

I don't know what exactly causes this error, since cors seems to be imported correctly, when I log it out. Also the value of process.env.REACT_APP_HOSTNAME is set correctly, to 'http://localhost:3000', in the logs.

The full code is available here:

Typescript Version (https://github.com/vincentrohde/hacktoberfest-checker)

Original (https://github.com/jenkoian/hacktoberfest-checker)

0 Answers
Related