One of the key tasks of a front-end developer is integrating back-end APIs. However, a lot of times your front-end application needs to communicate with a server that's of a different origin. This could be your own server or a third-party application programming interface you need in your application.
In all these cases, you may often run into a cross-origin resource sharing (CORS) error. But what exactly is CORS? And how can you interact with your back-end services in a hassle-free way? In this post, I'll talk about what CORS is and how you can enable it in your Angular application.
The Origin Story
Before we understand CORS, let's do a quick refresher on how most modern web applications work.
Server-Side Rendered Web Applications
Let's say you're working with a website that sells candy to users. You can have a server that consists of different server-side routes that send back different HTML pages. This is called server-side rendering because your server takes care of everything—serving static files, CSS styles, and images, fetching data from the database, and so on.
Server-side rendered web app.
The above shows how a server-side web app interacts with a user's browser. So when a user visits a web page on your site, your server sends back the desired HTML page.
Web Apps With Decoupled Front End and Back End
The more popular way to create modern web apps is to decouple the front end and back end of your application. Your back end is connected to a database where you store all the information about the candies you sell. Your front end makes a request to the back end to fetch the data and displays it to the user.
How modern web applications work.
As shown above, your front end makes an HTTP GET request to your back end to an endpoint, /candy. Your back end then queries the database and gives the front end a JSON response.
But wait—what is /candy ? That's not a complete URL, right?
Anatomy of a URL
Conventionally, when we say our front end is making a request to an endpoint that begins with /, it means the endpoint is hosted on the same domain as the front end. With respect to our previous example, we can say that both our front end and back end are hosted at mycandysite.com.
Front end and back end using the same domain.
However, there's more to a URL than just a domain. Since both our front end and back end are running on different servers, despite being on the same domain, they're differentiated by the port number. A URL always has the following three components:
scheme
domain
port
Here's how these three components look in an actual URL. In http://www.mycandysite.com:80, the HTTP part is the scheme, the www.mycandysite.com is the domain, and the 80 part is the port.
Anatomy of a URL.
The above three components together constitute the origin of the URL. If two URLs differ in any of the above three components, they have different origins. In the above example, our back end could be hosted at mycandysite.com:5000, and our front end could be hosted at mycandysite:8000. Both have different ports and therefore are of different origins.
Browsers' "Same Origin" Policy and CORS
Because of security measures, web browsers impose a "same origin" policy on all web apps. This policy states that a client on a browser can interact only with servers that have the same origin as the client. So in the previous case of a decoupled application, if your front end tries to request a resource from your server, the browser would throw an error. Since each is of a different origin, they aren't allowed to share resources with each other. We call this the CORS error.
CORS error due to browser's same origin policy.
To get around this, you need to tell your browser to enable your client and your server to share resources while being of different origins. In other words, you need to enable cross-origin resource sharing or CORS in your application. If you're still curious and want to learn more about CORS in theory, here's a great guide that dives deeper into the subject. What does a CORS error actually look like? Let's see it inside an Angular application.
CORS in Action
To see CORS in action, we need a small mock server as our back end. Let's create a simple NodeJS and Express application.
Create Mock Server
Inside a directory of your choice, run the following command:
mkdir cors-server && npm init -y && npm i express
Head over to the cors-server folder, and create an index.js file. Inside this file, add the following code:
const express=require('express');
const app=express();
const PORT=5000;
app.get('/',(req,res)=>{
res.send("Welcome to CORS server! 😁")
})
app.get('/candy',(req,res)=>{
res.json({'candy':'bubble-gum'})
})
app.listen(PORT,()=>console.log(`server running on port ${PORT}`))
We've created a server with an endpoint /candy that returns some JSON response. Let's run this server using the following command:
node index.js
And now, if you visit http://localhost:5000/candy, you'll get the following JSON response:
CORS server.
Great! Let's create an Angular application that makes a request to this endpoint.
Create Angular Application
Create a new Angular app by running
ng new angular-cors
Replace everything inside your app.component.html with the following:
<h1>Angular CORS App 😁</h1>
Next, let's head over to the app.component.ts file and make a request to our endpoint.
First, import the HttpClient module as shown:
import { HttpClient } from '@angular/common/http';
We'll need to inject this dependency in our component inside the constructor and create an instance of the dependency that we can later use.
constructor(private http:HttpClient){
}
Then, we'll create a function getCandy() and invoke it inside ngOnInit(). Inside the getCandy() function, we'll use the HttpClient instance http to make a request to our endpoint and log the result to the console. Since the getCandy() function is fired inside the ngOnInit(), we'll hit our server as soon as the <app-component/> mounts on the DOM.
ngOnInit(){
this.getCandy();
}
getCandy(){
this.http.get('http://localhost:5000/candy').subscribe(data=>{
console.log(data)
})
}
Finally, our app.component.ts file should look like this:
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(private http:HttpClient){
}
ngOnInit(){
this.getCandy();
}
getCandy(){
this.http.get('http://localhost:5000/candy').subscribe(data=>{
console.log(data)
})
}
}
Let's kick-start our angular application by running
ng serve --port 8000 -open
This should open our Angular application in the browser.
Visit http://localhost:8000 in your browser, and check the console. You'll find a CORS error thrown by the browser.
CORS error in Angular.
Also, the browser has blocked your request, and you won't be able to see the response of the request.
So, how do we fix this CORS error?
Proxy Requests to Enable CORS in Angular
When you're in development, frameworks provide you a neat little hack to get around CORS. If you're using React, luckily, I did a similar post on how to enable CORS in React. Basically, if our Angular application is running port 8000 and our back end is on 5000, we need to proxy requests from port 5000 to port 8000.
Does that sound complex? Let's demystify it! Inside the src folder of your application, create a new file called proxy.conf.json. This is a JSON file that'll contain the configuration for our proxy server. Here, we'll tell our Angular application to act as another server that takes API calls and diverts them to http://localhost:5000.
Inside the proxy.conf.json file, add the following code:
{
"/api": {
"target": "http://localhost:5000",
"secure": false
}
}
Next, we need to inform Angular about this proxy configuration. We can do that by adding a proxyConfig option inside our angular.json file.
...
"architect": {
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "your-application-name:build",
"proxyConfig": "src/proxy.conf.json"
},
...
That's it! All you need to do now is restart your server using the ng serve command.
Let's check back in our Angular application's console:
CORS enabled in Angular app.
There it is! We can now see the JSON response from the endpoint. This means that our Angular application successfully interacted with our back-end API while being of a different origin.
Drawbacks of Proxy Servers
The above method works great, but I hate to break it to you that it's only a development-time trick. This means you won't get away with CORS using a proxy server in production. Angular-CLI provides this type of configuration, but not for your production app bundles.
Due to this method's simplicity, it's great to use it to enable CORS in development. For a more logical and foolproof solution, though, you must always enable CORS on the server side.
Fix CORS on the Server Side
To enable CORS on the server side based on our server's configuration, we can set a Access-Control-Allow-Origin property on our response. When the browser receives the response, it receives this property in the headers of the request.
Let's go back to our NodeJS and Express server code. Let's update our request handler with the following code:
app.get('/candy',(req,res)=>{
res.set('Access-Control-Allow-Origin', 'http://localhost:8000');
res.json({'candy':'bubble-gum'})
})
Since we mention our front end's origin, we have now enabled our server to interact with any incoming requests from the client running on http://localhost:8000. You can set that value to be whatever you want, depending on which client you want to enable CORS for.
You can also use third-party packages like cors instead as a middleware for all your requests. First, you need to install this package by running:
npm i cors
Next, import it at the top as shown:
const cors=require('cors');
Then, you need to pass it inside your express app as a middleware:
app.use(cors())
Parting Advice
I hope this simplified CORS for you and showed how you can enable it in your Angular application. For quick prototyping or testing, you can safely use the proxy configuration. However, you must always aim to handle CORS from the server. In situations where you don't have access to server-side code, like a third-party API, you can implement a custom proxy server. All you need to do is make requests to your third-party API from this custom server and hit your own server to consume that data in your Angular application.
You can learn a lot more from StackHawk. Check out the useful blog, and find out how to start a free account.
This post was written by Siddhant Varma. Siddhant is a full stack JavaScript developer with expertise in frontend engineering. He’s worked with scaling multiple startups in India and has experience building products in the Ed-Tech and healthcare industries. Siddhant has a passion for teaching and a knack for writing. He's also taught programming to many graduates, helping them become better future developers.