This is a GraphQL backend boilerplate in nodeJS that can be deployed on AWS Lambda.
node 8.10
AWS RDS Postgres
AWS Lambda
Apollo Server (GraphQL framework)
Sequelize (Postgres ORM)
We consider a bank account schema where a user can transfer money to another user. This will involve writing a transfer
resolver which does complex business logic in a transaction.
type User {
id: Int
name: String
balance: Int
}
type Query {
hello: String
users: [User]
}
type Mutation {
addUser(name: String, balance: Int): User
transfer(userIdFrom: Int, userIdTo: Int, amount: Int): User
}
The sample source code is present in graphql.js
. Clone the repo and go to aws-nodejs/apollo-sequelize
folder:
$ git clone git@github.com:hasura/graphql-serverless
$ cd graphql-serverless/aws-nodejs/apollo-sequelize
- First, let's set the environment variable for connecting to the postgres instance on RDS. You can find this endpoint on your RDS instances page on AWS console:
$ export POSTGRES_CONNECTION_STRING='postgres://username:password@rds-database-endpoint.us-east-1.rds.amazonaws.com:5432/mydb'
- Next, lets create the tables required for our schema. The SQL commands are in
migrations.sql
file.
$ psql $POSTGRES_CONNECTION_STRING < ../../schema/migrations.sql
- Now, you can start a development environment by setting an environment variable before running the code:
$ export LAMBDA_LOCAL_DEVELOPMENT=1
- Now, you can run the code:
$ node graphql.js
Output:
Server ready at http://localhost:4000/
This will start a local server on localhost:4000
. You can hit the graphql service at localhost:4000
. This opens a graphql playground where you can query your schema.
Now, you can play with the schema and make any changes in the source code for additional functionalities as you desire.
Now that you have run the graphql service locally and made any required changes, it's time to deploy your service to AWS Lambda and get an endpoint. The easiest way to do this is through the AWS console.
- Create a Lambda function by clicking on Create Function on your Lambda console. Choose the
NodeJS 8.10
runtime andlambda_basic_execution
role.
- In the next page (or Lambda instance page), select API Gateway as the trigger.
- Configure the API Gateway as you wish. The simplest configuration is shown below.
Save your changes. You will receive a HTTPS endpoint for your lambda.
If you go to the endpoint, you will receive a "Hello from Lambda!" message. This is because we haven't uploaded any code yet!
- Zip and upload code. Make sure to set the handler as
graphql.handler
and add thePOSTGRES_CONNECTION_STRING
environment variable:
$ zip -r graphql.zip *
And that's it. Hit save and visit the endpoint again. You will see the graphql playground again.
IMPORTANT NOTE: You may have to edit the GraphQL URL in the Playground to reflect the right endpoint ( same as the URL created by the API Gateway ).
As discussed in the main readme, without connection pooling our GraphQL backend will not scale at the same rate as serverless invocations. With Postgres, we can add a standalone connection pooler like pgBouncer to accomplish this.
Deploying pgBouncer requires an EC2 instance. We can use the CloudFormation template present in this folder: cloudformation.json to deploy a pgBouncer EC2 instance in few clicks.
-
Goto CloudFormation in AWS Console and select Create Stack.
-
Upload the file cloudformation.json as the template.
-
In the next step, fill in your Postgres connection details:
-
You do not need any other configuration, so just continue by clicking NEXT and finally click CREATE.
-
After the creation is complete, you will see your new
POSTGRES_CONNECTION_STRING
in the output:
Now, change your POSTGRES_CONNECTION_STRING
in your lambda function to the new value. And, everything should just work!
Using pgBouncer, here are the results for corresponding rate of lambda invocations. The tests were conducted with the addAuthor
mutation using jmeter.
Error Rate -> | Without pgBouncer | With pgBouncer |
---|---|---|
100 req/s | 86% | 0% |
1000 req/s | 92% | 4% |
10000 req/s | NA | 3% |