CORS is a Pain for Side Projects
Tags: cors, aws, react, sideprojects
Published: 2020-03-21 16:05:17

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:
```console
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.

```javascript
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.

```javascript
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](https://github.com/axios/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.

```javascript
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:

```javascript
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](https://reactjs.org/docs/hooks-intro.html).

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](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) 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 ✌🏻