Bob
Bob

Reputation: 482

Why is CORS not working on my express/react app?

I am using the npm cors package with my react app and express (OOP approach), but I still get the CORS error:

Access to XMLHttpRequest at 'http://localhost:8000/api/auth/authenticate' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

enter image description here

I have cors() set up on the backend, at localhost:8000. I am calling the api with { withCredentials: true } on the front end, at localhost:3000.

So I am not sure where did it go wrong.

My setup below. Thanks,

Backend - express.middleware.ts

import cors from "cors";
import express from "express";

module.exports = (app: any) => {
  app.use(
    cors({
      origin: "http://localhost:3000",
      methods: ["POST", "PUT", "GET", "OPTIONS", "HEAD"],
      credentials: true,
    })
  );

  app.use(express.static("public"));
};

Backend - app.ts

import express from "express";
import dotenv from "dotenv";
import path from "path";

class App {
  private _app: express.Application;
  private readonly _port: number | string = process.env.PORT || 8000;

  constructor(controllers: any[]) {
    this._app = express();
    dotenv.config();

    this.initializeControllers(controllers);
    this.initializeMiddleWares();
  }

  public start() {
    this._app.listen(this._port, () => {
      console.log(`App listening on the port ${this._port}`);
    });
  }

  private initializeControllers(controllers: any[]) {
    controllers.forEach((controller) => {
      this._app.use("/api", controller.router);
    });
  }

  public initializeMiddleWares() {
    require("./src/middleware/express.middleware")(this._app);
  }
}

export default App;

Backend - server.ts

import App from "./app";
import AuthController from "./src/modules/auth/auth.controller";
import { AuthService } from "./src/modules/auth/auth.service";

const server = new App([new AuthController(new AuthService())]);

server.start();

Frontend - useGet.ts(custom hook to call api)

import React from "react";
import { useHistory } from "react-router-dom";
import axios from "axios";
import { server_url } from "../constants";

const useGet = () => {
  const history = useHistory();
  const doGet = (path: string, cb?: Function) => {

    axios
      .get(`${server_url}${path}`, { withCredentials: true })
      .then((response) => {
        if (cb) {
          cb(response.data);
        }
      })
      .catch((err) => {
        console.log(err);
      });
  };

  return [doGet];
};

export default useGet;

Upvotes: 2

Views: 1750

Answers (1)

acdcjunior
acdcjunior

Reputation: 135752

Initialize the middleware before configuring the routes.

From the docs:

If the current middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function. Otherwise, the request will be left hanging.

In your case, the controllers do end the request-response cycle, thus the middleware never gets to act.

To fix it, change this:

class App {
  // ...
  constructor(controllers: any[]) {
    // ...
    this.initializeControllers(controllers);
    this.initializeMiddleWares();
  }

into this (notice the order of the lines):

class App {
  // ...
  constructor(controllers: any[]) {
    // ...
    this.initializeMiddleWares();
    this.initializeControllers(controllers);
  }

And you should be good to go.

Upvotes: 2

Related Questions