I have been working on the front-end quite a bit lately and as such I have often come across the CORS issue. Lately, I have solved that problem with Node, so in this post, I will share my solutions.

Background

Every once in a while, I have to build a web based MVP solution that fetches data from an external URL which is when I run into the CORS issue. Now, this issue takes the momentum away from the work I am doing because I don’t always have a solution ready for this problem, so I need to build a solution for it. Most of the time, I build a solution using NodeJS and this time, I thought I would create something that I can use every time I face this problem. Anyway before I get into the solution for this, let’s learn a little bit about CORS.

What is CORS?

Cross-Origin Resource Sharing (CORS)…hmmm, how can we understand this? Honestly, it’s difficult for me to formulate the exact technical description of this. Let me try…. think of it as a method that uses additional HTTP headers to tell the browser that, your site running at your url, is trying to get resources from a different url.  Say we have a site running on http://localhost:80/ and some examples of a CORS request would be,

  1. Getting data from http://example.com/info/user.json because trying to get data from a different host
  2. Getting data from http://localhost:3000/user.json because trying to get data from a it’s a different port
  3. Getting data from https://api.secure.com/info/user.json because trying to get data from a different protocol

When trying to fetch data from the above URLs using client-side Javascript and through methods such as XMLHttpRequest or Fetch API, the browser restricts it. It does so for security reasons, not for the client’s security but for the server. Makes sense doesn’t it? I mean, if client-side Javascript could get data from any other site, then how would the site differentiate between the requests coming from it’s own client-side Javascript vs some external Javascript from a foreign location.

This is when when developing a Javascript based MVP locally, I come across this problem. I have a Javascript function e.g.

async function uploadWithFetch("http://example.com/info/user.json", data) {
    let resp = await fetch(url, {
        method: 'POST',
        body: JSON.stringify(data)
    });
    return resp.json();
}

which runs locally and is trying to retrieve data from an external host, causing the CORS error.

Like the blog? Subscribe for updates

Bypassing CORS on Web

Node is great and it’s quite easy to build proxies that let us bypass CORS while accessing external API. I created two NodeJS based proxies. They both use the Express middleware below is the NodeJS code for each one of those proxies.

Like the blog? Subscribe for updates

With CORS middleware

var express = require("express");
var cors = require("cors");
var axios = require("axios");

var app = express();
app.use(cors());

const UPLOAD_URL = "http://example.com/info/user.json";
/*
Axios response object, properties
data, status, statusText, headers, request
http://zetcode.com/javascript/axios/
*/
app.post("/create", function(req, res) {
    axios.post(UPLOAD_URL, req.body).then(response => {
        if(response.status === 200) {
            res.send(response.data);
        } 
    }).catch(err => {
        console.log("Error making the request");
        res.send(err);
    })
});

const port = 3000;
app.listen(port, () => {
    console.log(`Listening on ${port}`);
});

This solution uses the CORS middleware and axios to make a post request. I like working with axios, it’s promised based and I suppose it’s just personal taste and I like working with Promise based APIs.

async function uploadWithFetch("http://localhost:3000/create", data) {
    let resp = await fetch(url, {
        method: 'POST',
        body: JSON.stringify(data)
    });
    return resp.json();
}

p.s. Thanks to my former research colleague Jayen Ashar (I didn’t know about the CORS middle-ware) for his help with this post. Checkout his profile he’s got heaps of experience and he understands the web well .

Without CORS middleware

const UPLOAD_URL = "http://exanple.com/info/user.json";
var express = require("express");
var app = express();

var request = require("request");

/* 
Read this: https://expressjs.com/en/api.html#req
without this we won't be able to read the request body 
passed in */
app.use(express.json()); // to parse application/json

app.use(function(req, res, next) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.header("Access-Control-Allow-Methods", "GET, PUT, PATCH, POST, DELETE");
    res.header("Access-Control-Allow-Headers", req.header('access-control-request-headers'));
    next();
});

app.post('/create', function(req, res) {
    let options = {
        url: UPLOAD_URL,
        form: req.body
    };
    request.post(options, function(error, response, body){
        try {
            let parsedResponse = JSON.parse(body);
            res.send(parsedResponse);
        } catch (error) {
            console.log(`Got an error -> ${error.status}`);
            res.send({"message":"error parsing json", "errorObj": error});
        }
    });
}); 
const port = 3000;
app.listen(port, function() {
    console.log(`Listening on port ${port}`);
});

In this one, we do not use the CORS middleware but rather set the Node headers ourselves. Once we start this NodeJS server, the client-side Javascript would look like this

async function uploadWithFetch("http://localhost:3000/create", data) {
    let resp = await fetch(url, {
        method: 'POST',
        body: JSON.stringify(data)
    });
    return resp.json();
}

Summary

To sum it all up, we only encounter the CORS error when requesting external resources from client-side Javascript. The browsers enforces this in order to safeguard the server and to prevent it from spoofing attacks. This is not an issue when making these requests from the server. Hence, in this post we looked how we can bypass the CORS using NodeJS based proxies. Hope you found this post useful and I would love to know your thoughts on how you managed to solve this issue when you ran into it during development? Please leave a comment on this post and let me know how you have solved this issue.

You can look at some of Github repositories where I have solved this problem.

  1. corsProxy.js on react-au-postcode-validator: Someone asked me to build this for a front-end engineer role https://github.com/cptdanko/react-au-postcode-validator
  2. cors-axios-proxy.js and cors-proxy.js on HTMLFormAndVanillaJS: Someone asked me to build this for a role https://github.com/cptdanko/HTMLFormAndVanillaJS

Like the blog? Subscribe for updates

As usual, if you find any of my posts useful support me by  buying or even trying one of my apps on the App Store. 

https://mydaytodo.com/apps/

Also, if you can leave a review on the App Store or Google Play Store, that would help too.


0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *