DEV Community

loading...
Cover image for CORS is a Pain for Side Projects

CORS is a Pain for Side Projects

Szabi
software dev at a consultancy, building front-end solutions; learning AWS;
・5 min read

If you are even a slightly bit adventurous web developer you must have faced this problem before and maybe you solved it and got on with your development or maybe you were like me who just gave up at that point because anyway is just a side project and I could just start using a framework where the back-end & front-end has the same origin and I can skip this problem all together.

This time I was a bit more serious about my side project, My Habit Tracker and I decided to go all the way and fix this issue.

Spoiler alert: It's pretty simple actually.

We are going to create a browser based front-end web app that'll send a request to an end-point in the cloud. Technologies that are involved in this project:

  • AWS API Gateway
  • AWS Lambda
  • React (w. create-react-app)
  • Axios

First step is to create a React app using create-react-app. In order to achieve that run the following commands in your terminal:

npx create-react-app poc-cors-app
cd poc-cors-app
yarn start

The app will be served in your browser on http://localhost:3000/, this is going to be domain number 1.

After we've seen the react logo spinning around, let's edit the App.js file to get rid of all unnecessary UI elements. Also we will have to use the useState hook because the data what we want to show is going to come from the cloud and will be updated after our request had a successful response. So basically we are turning the App component into a stateful component but thanks to react hooks we can keep the function syntax.

import React, { useState } from 'react';
import './App.css';

function App() {

  const [ data, setData ] = useState('CORS not yet enabled');

  return (
    <div className="App">
      <header className="App-header">
        <p>
          {data}
        </p>
      </header>
    </div>
  );
}

export default App;

The command line will warn you about not using the setData but don't worry, we are going to get back to this. Now let's create our back-end services.

Login to AWS console and under Service find Lambda which will always be under the Compute section. When you navigate to Lambda you will be able to create a new function by clicking Create function on the top right corner of the page. Name the function poc-cors-getData and hit the Create function button.

After your lambda function has been created edit the function code to match the following line.

exports.handler = async (event) => {
    const response = {
        statusCode: 200,
        body: 'CORS is enabled yeeey!',
    };
    return response;
};

Next up head to API Gateway which you'll find in Network and Content Delivery section and create a new REST API named poc-cors-api which works with Lambda.
By clicking the Actions dropdown add a new Resource to the api called end-point and leave the rest of the form as default. Select the newly created Resource and add a GET Method to it by clicking the Actions dropdown again. Before you can save the method you need to attach the lambda function what we've created previously by providing the name of the function, poc-cors-getData.

Okay, let's deploy our API (Actions dropdown), we can call the deployment stage dev for the sake of this example. The dev stage will provide you an Invoke URL which you can use to test your API in Postman i.e, or just simply copy it to your browser and append /end-point to the end of the URL, and this is your domain number 2. Hopefully you get back the response what the Lambda function has. If not, make sure all the names are identical.

Alright, back to the front-end

Now we have to make a request to this API from our React app and in order to do this we are going to use axios, add the package to the project using yarn in your terminal.

yarn add axios

In your App.js file make sure that you additionally import axios and useEffects hook.

import React, { useState, useEffect } from 'react';
import axios from 'axios';

Let's make the request by inserting the following piece of code after you call the useState and before you return the UI:

useEffect(() => {
  async function fetchData() {
    const response = await axios.get('https://YOUR_INVOKE_URL_ID.execute-api.eu-west-1.amazonaws.com/dev/end-point');

    setData(response.data.body);
  }

  fetchData();
});

If you are not familiar with React Hooks I would recommend going through the compact and informative docs here.

When you serve the web app now you'll find that the CORS not yet enabled text is visible in the middle of the page and if you open up developer tools and navigate to the Console you'll see an error indicating that your request has been blocked by CORS (Cross Origin Resource Sharing). This happens because your front-end and cloud service are on two different domains and your browser blocks the request by default.

If you want to dive into the details I can recommend this article which has a bunch of information on the topic.

Luckily AWS made it very easy for us developers to Enable CORS on different API Gateway resources. In order to set this up we have to go back to AWS Console.

Cool, switch to the back-end

Select your Resource that you want to enable CORS on, /end-point in our situation and open the Actions dropdown where you'll find the Enable CORS Resource Action, click on it. Leave all the settings as default and tap on Enable CORS and replace existing CORS headers button. This will create an OPTIONS Method which will have all the necessary Response Headers for letting your request from the browser to get a successful response.

Finally, deploy the API (Actions dropdown). Refresh your browser and hopefully see the string that is returned in the response body from the Lambda function.


Hope this short guide on how to start local web development using AWS services and React was useful. Please let me know in the comments if you got stuck at a certain step and I'll try my best to help you figure out what went wrong.

Also, I would appreciate some feedback on how easy it was to follow this guide without any AWS Console screenshots?

Thanks a lot for reading! 📖 Happy coding everyone ✌🏻

Discussion (2)

Collapse
baso53 profile image
Sebastijan Grabar

Which domains and HTTP methods will be allowed on the specified endpoint? I assume all origins and all methods, otherwise I don't know how would this work. I had a big discussion at work about CORS, nobody actually understood it fully, but now everyone has a pretty good idea.

The reason why I don't think the thing you suggested is a good idea is because you basically threw out Same-Origin policy that the browsers enforce and it's a VERY good thing they do. I think the best thing to do would be to never turn CORS on, until you actually deploy something to production. Even then, maybe you can configure that the backend and frontend are served from the same origin and BAM, you don't even need CORS.

Now, I know that this post is about setting up CORS for side projects and the thing you specified is fine, but even better would be to use an option available in create-react-app, which is to use a proxy (create-react-app.dev/docs/proxying...). Angular CLI projects have the same thing available.

Or maybe even simpler, but not necessarily better, is to use a browser extension which turns off the same-origin policy, it's a 5 second job. Just be sure it's not turned on when you're testing things in production.

Collapse
szabikr profile image
Szabi Author

Thank you for your response Seb, very informative and highlights the fact that the enabling CORS is not a great idea in a real life scenario. For example this end-point what we've created in the tutorial is going to allow requests from all origins and the supported methods are GET and POST.

This solution provides me the ability to build, test and try out absolutely vital functionality first, without buying a domain name or getting close to production stage at all. With this guide everybody can start working on a web application within a few minutes and focus on real functionality.

I am going to check out the proxy solution in create-react-app, that is probably a more elegant and safer way of getting the problem out of the way.