title: Angular app can't read Django Rest Framework API because of CORS issue
body: <p>I'm experiencing a CORS issue consuming a Django Rest Framework REST API from an Angular 6 app.</p>
  
  <p>The API runs on <a href="http://localhost:55098/admin" rel="nofollow noreferrer">http://localhost:55098/admin</a>. It works fine when I invoke it with Insomnia. Angular app runs on <a href="http://localhost:4200" rel="nofollow noreferrer">http://localhost:4200</a>.</p>
  
  <p>When I first typed <a href="http://localhost:4200/cgestores" rel="nofollow noreferrer">http://localhost:4200/cgestores</a> it should redirect to <a href="http://localhost:55098/admin/cgestores" rel="nofollow noreferrer">http://localhost:55098/admin/cgestores</a>, and it did, but I got a CORS error message (see below).</p>
  
  <p>My configuration:</p>
  
  <p><strong>REST API</strong>: I'm using Python 3.7 (64 bit), Django (2.1.5) and Django Rest Framework (3.9.1)</p>
  
  <p>My settings.py:</p>
  
  <pre><code>ALLOWED_HOSTS = [
      'testserver',
      'localhost'
      ]
  
  CORS_ORIGIN_ALLOW_ALL = True
  
  INSTALLED_APPS = [
      # Add your apps here to enable them
      'django.contrib.admin',
      'django.contrib.auth',
      'django.contrib.contenttypes',
      'django.contrib.sessions',
      'django.contrib.messages',
      'django.contrib.staticfiles',
      'rest_framework',
      'rest_framework_swagger',
      'corsheaders',
      'admin_v20',
  ]
  
  MIDDLEWARE_CLASSES = [
      'django.middleware.security.SecurityMiddleware',
      'django.contrib.sessions.middleware.SessionMiddleware',
      'corsheaders.middleware.CorsMiddleware',
      'django.middleware.common.CommonMiddleware',
      'django.middleware.csrf.CsrfViewMiddleware',
      'django.contrib.auth.middleware.AuthenticationMiddleware',
      'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
      'django.contrib.messages.middleware.MessageMiddleware',
      'django.middleware.clickjacking.XFrameOptionsMiddleware',
  ]
  </code></pre>
  
  <p><strong>Angular client</strong>: I'm using Angular 6.4.1. The service (apiusuarios.service.ts):</p>
  
  <pre><code>import { Injectable } from '@angular/core';
  import { HttpClient, HttpHeaders, HttpErrorResponse, HttpParams } from '@angular/common/http';
  import { Observable, of } from 'rxjs';
  import { map } from 'rxjs/operators';
  
  @Injectable({
    providedIn: 'root'
  })
  
  export class ApiusuariosService {
  
    datos: iCentroGestor;
  
    constructor(private http: HttpClient) { }
  
    getMock(): any{
      return [
        {"gececo":"a", "gecdes":"one"},
        {"gececo":"b", "gecdes":"two"},
        {"gececo":"c", "gecdes":"three"}
      ];
    }
  
    getUsers(): Observable&lt;any&gt; {
      return this.http.get(endpoint + 'cgestores').pipe(map(this.extractData));
    }
  
  }
  
  export interface iCentroGestor {
    gececo: string;
    gecdes: string;
  }
  
  const endpoint = 'http://localhost:55098/admin/';
  </code></pre>
  
  <p>Method <code>getMock()</code> returns a fixed JSON value just for test purposes, and it works fine. The method that actually calls the API is <code>getUsers()</code>, and is the method that triggers the CORS error:</p>
  
  <p><strong>Access to XMLHttpRequest at '<a href="http://localhost:55098/admin/cgestores/" rel="nofollow noreferrer">http://localhost:55098/admin/cgestores/</a>' from origin '<a href="http://localhost:4200" rel="nofollow noreferrer">http://localhost:4200</a>' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.</strong></p>
  
  <p>(that's Chrome; Firefox and Edge return similar responses)</p>
  
  <p>This seemed to be an issue for a lot of people, I checked these articles:</p>
  
  <ul>
  <li><a href="https://github.com/crs4/ome_seadragon/wiki/Enable-Django-CORS-(Cross-Origin-Resource-Sharing)-Headers-configuration" rel="nofollow noreferrer">https://github.com/crs4/ome_seadragon/wiki/Enable-Django-CORS-(Cross-Origin-Resource-Sharing)-Headers-configuration</a>  </li>
  <li><a href="https://www.techiediaries.com/django-cors/" rel="nofollow noreferrer">https://www.techiediaries.com/django-cors/</a>  </li>
  <li><a href="https://stackoverflow.com/questions/35521935/cors-django-access-control-allow-origin">CORS django &#39;Access-Control-Allow-Origin&#39;</a>  </li>
  <li><a href="https://stackoverflow.com/questions/49519850/no-access-control-allow-origin-using-django-rest-framework-api">No &#39;Access-Control-Allow-Origin&#39; using django rest framework api</a>  </li>
  <li><a href="https://stackoverflow.com/questions/43357687/django-python-rest-framework-no-access-control-allow-origin-header-is-present">Django Python rest framework, No &#39;Access-Control-Allow-Origin&#39; header is present on the requested resource in chrome, works in firefox</a>  </li>
  <li><a href="https://stackoverflow.com/questions/33375797/django-rest-framework-xmlhttprequest-cannot-load-http-127-0-0-18000-xyz-api/33377351#33377351">Django Rest Framework: XMLHttpRequest cannot load http://127.0.0.1:8000/xyz/api/abc</a></li>
  </ul>
  
  <p>...and a few more, and also this video:</p>
  
  <ul>
  <li><a href="https://www.youtube.com/watch?v=OIbndrrUYiY" rel="nofollow noreferrer">https://www.youtube.com/watch?v=OIbndrrUYiY</a></li>
  </ul>
  
  <p>...and they all pretty much sayed the same: it's not an Angular problem, it's a server issue, and I should make the following modifications to my DRF project:</p>
  
  <ol>
  <li><p>Install CORS headers package</p></li>
  <li><p>Modify settings.py with the following:  </p>
  
  <ul>
  <li>Add CORS_ORIGIN_WHITELIST  </li>
  <li>Add corsheaders to INSTALLED_APPS  </li>
  <li>Add corsheaders.middleware.CorsMiddleware to MIDLEWARE_CLASSES  </li>
  </ul></li>
  </ol>
  
  <p>All done, but it still didn't work. After trying all that, I read that I could specify the header that I need on my response. So I tried this in my DRF project:</p>
  
  <pre><code>return Response(data=pDatos, status=pStatus, headers={"Access-Control-Allow-Origin":"*"})
  </code></pre>
  
  <p>... and bingo, it worked!  </p>
  
  <p>However, this is not really a solution, I don't like to have to depend on a specific parameter on a specific response. And, on top of that, I have no way to restrict who can access the site and who can't, which would be really easy to do with CORS_ORIGIN_WHITELIST (well, I could, but writing a parameter with a list of sites in place of the asterisk symbol doesn't seem to be the right option).  </p>
  
  <p>So, what am I doing wrong? Why do my <code>settings.py</code> options not work? I commented them out, and just left the <code>return Response...</code> and it still works, so <code>settings.py</code> is not really doing anything.  </p>
  
  <p>Sorry for this long post. Any ideas? Thanks in advance for your help.</p>