One day, my teammate mentioned me several times and said that the backend API was not reachable. It was strange because I had tested it an hour earlier and everything was working fine. When I saw the error screenshot, I realized that the API itself was fine, but somehow it couldn’t be called by Vue.js.

After some investigation, we found that it was a CORS (Cross-Origin Resource Sharing) issue, which is common in decoupled projects.

Why the CORS issue happens

CORS issues happen in decoupled (or headless) projects because the frontend and backend run on different origins (i.e., different domains, ports, or protocols). Browsers enforce a same-origin policy for security, and CORS is a mechanism that allows servers to indicate they are okay with being called from a different origin. Here is why it happens,

Different origins

  • Frontend: http://localhost:3000
  • Backend/API: http://localhost:8000
    Even though both are on localhost, the different ports make them different origins.

Browser security policy
The browser blocks frontend JavaScript from accessing backend resources unless the backend explicitly allows it via CORS headers.

Missing or incorrect CORS headers
The backend needs to send headers like:

Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization

Preflight requests
Some requests (e.g., with custom headers or non-simple methods like PUT) trigger a preflight OPTIONS request. If the backend >doesn’t handle this properly, the actual request will be blocked.

Credentials issue
If you’re using cookies or HTTP authentication, you need to allow credentials explicitly:

  • Frontend: fetch(url, { credentials: “include” })
  • Backend: Access-Control-Allow-Credentials: true

How to solve the CORS issue

  • On the backend, use CORS middleware or configuration depending on your stack (e.g., Express.js, Django, Flask, Laravel).
  • Always whitelist the correct origin or use “*” for public APIs (not recommended if credentials are involved).
  • Handle OPTIONS requests correctly.
  • Be mindful of environment differences (dev vs. prod).

In our practice, we made some changes by adding headers to the backend code.

INSTALLED_APPS = [
    ...
    'corsheaders',
    ...
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    ...
]

CORS_ALLOW_ALL_ORIGINS = True

Some findings and thoughts

  • CORS is a common issue in decoupled architectures, and we need to handle it carefully.
  • Communication is important for solving problems together, rather than struggling alone.