- Install your node dependencies, run
npm install
. - Start up your development server by running
npm run dev
. - Start up webpack watch process in another terminal by running
npm run watch
. - Navigate to
http://localhost:5000/
and you should see the frontend React components rendering successfully.
- To kick off the test suite run
npm run test
.
This repository leverages the Serverless Framework. You can deploy this application to a live endpoint with this simple command sls deploy
. You may need to first enter your platform credentials for this to deploy successfully.
The sls deploy
command will use the specified serverless.yml
configuration file to build the infrastructure for all of your lambda functions and specified API Gateway endpoints.
Here we utilize AWS exclusively, but you can switch these AWS Lambda functions out or mix and match with any FAAS platform including Azure Functions, Google CloudFunctions and more.
View more Serverless commands here.
- Run
sls deploy
. - Enter your AWS Credentials if you are prompted to do so.
- Serverless will then deploy your app to AWS and will output a live URL you can navigate to and view your app.
The frontend for this application is pretty straighforward. We build our React application using Webpack, which bundles our script into a single file. This file is then hosted on AWS's S3 storage system and delivered to the client through AWS's API Gateway. This is a lightweight Single-Page Application.
The backend of this application is documented in our serverless.yml
file. This file is our "architecture as code". We specify everything in it included the url's we want our individual lambda functions to live, the environment variables we need, the services we need permissions for and more.
The Serverless Framework uses this file to hoist all of our infrastructure to support our lambda functions.
All of our Lambda functions live in the root /functions
folder.
The functions supplied within this boilerplate cover all of the neccessary abilities needed for the initial rendering of our frontend React App on a live endpoint.
This boilerplate has a /global-variables
file where you can store the base url endpoint for AWS API Gateway.
This allows you to easily move the project and endpoints to another location by defining the base path and other important endpoints in one place.
This means you can get the baseURL anywhere within the frontend React code like this utils.baseAPI
.
There are many advantages of using an architecture like this.
Cost.
Since Lambdas never run unless they are being used, you will never pay for server uptime you aren't actively using. This is very different from traditional applications that always have a server running regardless of usage and provides you with significant cost savings, especially at scale.
Scalability.
AWS handles the scalability of Lambdas out of the box. You could see sudden spikes in traffic and never encounter any server downtime or latency. As a matter of fact, your lambdas will actually become more performant the more frequently they are used.
Flexibility.
This architecture is inherently flexible. You can decouple the frontend and backend very easily and even spin up a completely new staging environment to test out a new endpoint. The Serverless Framework has some very handy commands that make this possible by leveraging AWS's sprawling ecosystem of products.
I'm documenting cors here because someone... somewhere will run into this issue again.
We are going to start on the client that makes the request and go all the way through the API Gateway => Lambda function => Response flow.
We are inside React here and making the request from the browser fetch API.
const response = await fetch(awsPaymentEndpointHere, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*" // Required for CORS support to work
},
body: JSON.stringify({
message: "We did it!"
})
});
const paymentResponse = await response.json();
In your lambda function response:
module.exports.handler = async function(event, context, callback) {
callback(null, {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Credentials": true,
"Content-Type": "application/json"
},
body: JSON.stringify({
message: "Successful Payment"
})
});
};
Simple enough.
Now onto the API Gateway configuration. You may not need to do this manually as Serverless should handle this configuration. However, if your endpoints are returning CORS errors, you may need to manually follow the steps below.
In the API gateway dashboard, navigate to your API and click on "Resources".
- Find your API Resources List.
- Go into
OPTIONS
for the endpoint you are working with; for this example it's/payment-processing
. - Click
Method Request
in the execution view. - Dropdown in
Request Body
:Content type
:application/json
andModel name
:Empty
. - Now click "<- Method Execution" and go back to main view.
- Click "Integration Request"
- Change
Request body passthrough
:When no template matches the request Content-Type header
. - Add Mapping template of
Content-Type
ofapplication/json
. - Now click "<- Method Execution" and go back to main view.
Click "Integration Response" (if you are inPOST
instead ofOPTIONS
skip these steps). - Set
Content handling
toConvert to text (if needed)
. - Set Header Mappings to:
Access-Control-Allow-Headers
: 'Access-Control-Allow-Origin,Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'
Access-Control-Allow-Origin
: '*'
Access-Control-Allow-Credentials
: 'false'
Access-Control-Allow-Methods
: 'OPTIONS,POST'
- Set Mapping Templates
Content-Type
to"application/json"
. - Set
Method Response
to return 200 inHTTP Status
field. Then addAccess-Control-Allow-Headers
Access-Control-Allow-Origin
Access-Control-Allow-Origin
Access-Control-Allow-Credentials
Access-Control-Allow-Methods
That's it!