How to fix the CORS error when using API Gateway with Lambda
In this article, we will learn how to fix the CORS issue using AWS Lambda with API Gateway. Here is the TLDR version.
- Add default CORS Pre-flight Options to REST API
- Return
Access-Control-Allow-Origin
header from lambda function allowing your domainYou can read rest of the article for more details.
What is CORS?
Let's say you have your API gateway at https://<random-id>.execute-api.us-east-1.amazonaws.com
 and your single-page application hosted in S3 backed by CloudFront at your domain www.your-domain.com
When you try to access the backend API through API Gateway from your react application, you may face Cross-Origin Resource Sharing(CORS) error.
CORS is a mechanism which allows a server to mention about any origin(combination of domain, scheme and port) that it want to allow a browser to load the contents from it. I strongly recommend to read this article on CORS to understand it better.
CDK Application replicating CORS issue
Let's create a simple CDK application to replicate this issue.
In below code snippet, we're creating a simple REST API with Lambda integration.
const getMoviesFn = new NodejsFunction(this, "getMoviesFn", {
entry: path.join(__dirname, "../lambdas", "get-movies.ts"),
functionName: "getMoviesFn",
});
const api = new RestApi(this, "moviesApi", {
restApiName: "movies-api",
});
const moviesIntegration = new LambdaIntegration(getMoviesFn);
const moviesResource = api.root.addResource("movies");
moviesResource.addMethod("GET", moviesIntegration);
Lambda function source code
This lambda function is pretty simple and it just returns the list of movies
export const handler = async (event: any) => {
const movies = [
{
id: 1,
name: "The Matrix",
},
{
id: 2,
name: "The Matrix Reloaded",
},
{
id: 3,
name: "The Matrix Revolutions",
},
];
return {
statusCode: 200,
body: JSON.stringify(movies),
};
};
When I fire a GET
request in Postman, I'm getting response as expected
When I try to call the same API endpoint from react application using client side javascript, I'm getting below error
Above error is the CORS error. In plain english, the API endpoint doesn't allow requests from http://localhost:3000.
If you're using Lambda Proxy Integration, as we've used - you need to do below things
- Add default Cors Prelight Options to REST API
- Return additional headers from lambda function
Add Default CORS PreFlight Options to REST API:
You can add preflight options to REST API by adding property defaultCorsPreflightOptions
- I've added 3 properties - allowOrigins
, allowMethods
and allowHeaders
const api = new RestApi(this, "moviesApi", {
restApiName: "movies-api",
defaultCorsPreflightOptions: {
allowOrigins: ["http://localhost:3000"],
allowMethods: ["OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE"],
allowHeaders: Cors.DEFAULT_HEADERS,
},
});
In the above code snippet, I've added my localhost address to the list so that I can call API Gateway endpoints from my react application.
I've added few methods to be allowed. You can configure as per your needs. For example, you may want to allow read operations, Â and not create/update/delete operations from other domains - you can remove POST, PUT, PATCH, DELETE from that list.
And I finally I allow the default headers.
Return additional header from lambda function
In the lambda function, you can add Access-Control-Allow-Origin
header to be returned from the lambda function as shown in below code snippet.
export const handler = async (event: any) => {
const metaData = {
headers: {
"Access-Control-Allow-Origin": "http://localhost:3000",
},
};
return {
...metaData,
statusCode: 200,
body: JSON.stringify(movies),
};
};
After deploying these changes, when I access the API endpoint from javascript in client side react application, I'm able to get the results as shown below
Please let me know your thoughts in comments.