As I approached the finale of my Apollo Odyssey GraphQL journey, my adventure took an unexpected turn. Due to a recent event involving Heroku and GitHub tokens, Heroku has revoked all OAuth tokens and disabled the feature for the foreseeable future. This hiccup presented itself as an opportunity for me to challenge myself and test my newly acquired Amazon Web Service skills.After some research, I choose to use AWS Lambda to deploy our GraphQL server and AWS Amplify to deploy our React application. There are other ways to get our application online (I believe you can do it with just AWS Amplify), but these tools provided the simplest and most streamline process. This post is to serve as a walk through for finishing our Space Odyssey adventure using AWS instead of Heroku. Part 1 covers deploying the backend server with AWS Lambda and Part 2 covers deploying our React Application to AWS Amplify, putting our FULL Stack Application into action!
Prerequisites
- Complete all lessons up to Apollo GraphQL tutorial – Lift Off Part 5 – Lesson Deploying Apollo Server
- Setup an AWS account
- Install the AWS CLI
- Configure the AWS CLI with user credentials
- Install the serverless framework from NPM by running the following command
npm install apollo-server-lambda
Next, we will create a file that must be named ‘graphql.js’ in the root of our server project (not in the src folder!) This file will be used for configuring later. Copy and paste the following into your graphql.js file.
Setting up Apollo Server Lambda
In this tutorial, we’ll be deploying our GraphQL server to AWS Lambda. To start, navigate to your odyssey-lift-off-part5-server’s root folder and install the apollo-server-lambda package
npm install apollo-server-lambda
Next, we will create a file that must be named ‘graphql.js’ in the root of our server project (not in the src folder!) This file will be used for configuring our server later. Copy and paste the following into your graphql.js file.
// graphql.js
const { ApolloServer } = require('apollo-server-lambda');
const server = new ApolloServer();
exports.graphqlHandler = server.createHandler();
Note that the ApolloServer is being imported from the apollo-server-lambda package we just installed. Also notice that the last line exports a named graphqlHandler with a Lambda function handler!
Before we put it all together, there is one more key change we need to make. In our src/schema.js file, we import from the apollo-server-lambda package instead of the apollo-server package. This requires us to change
// src/schema.js
const { gql } = require('apollo-server');
to
// src/schema.js
const { gql } = require('apollo-server-lambda');
Now let’s connect the rest of our app.
In our newly created graphql.js file, let’s import our Type Definitions that we previously defined in our schema, our datasources (our TrackAPI), and our resolvers.
// graphql.js
const { ApolloServer } = require('apollo-server-lambda');
const typeDefs = require('./src/schema')
const TrackAPI = require('./src/datasources/track-api');
const resolvers = require('./src/resolvers')
Now we are ready to plug these variables into our ApolloServer instance.
// graphql.js
// ...
const server = new ApolloServer({
typeDefs,
resolvers,
dataSources: () => {
return {
trackAPI: new TrackAPI(),
};
},
});
Our completed
grapqhl.js file should look like this:
// graphql.js
const { ApolloServer } = require('apollo-server-lambda');
const resolvers = require('./src/resolvers');
const TrackAPI = require('./src/datasources/track-api');
const typeDefs = require('./src/schema');
const server = new ApolloServer({
typeDefs,
resolvers,
dataSources: () => {
return {
trackAPI: new TrackAPI(),
};
},
});
exports.graphqlHandler = server.createHandler();
Deploying with the Serverless Framework
Serverless is a framework that makes deploying to services like AWS Lambda simpler.
To do this, we need to create a config file named ‘serverless.yml’ in our root directory to determine what service to deploy to and where the handlers are.
To avoid getting to far into the weeds, the following file can be copied and pasted into the root of your project.
# serverless.yml
service: apollo-lambda
provider:
name: aws
runtime: nodejs14.x
functions:
graphql:
# this is formatted as <FILENAME>.<HANDLER>
handler: graphql.graphqlHandler
events:
- http:
path: /
method: post
cors: true
- http:
path: /
method: get
cors: true
After you have created this file in your server’s root directory, you are ready to deploy. Run the following command
serverless deploy
This command may take a few minutes to finish. This command builds the functions, zips up the artifacts, and uploads the artifacts to a new S3 bucket. Then it creates a CloudFormation Stack, connecting our new Lambda function with those artifacts and, if successful, outputs the HTTP endpoint URLs to the console. You can view the created S3 bucket and Lambda function and CloudFormation on your AWS account.
(Note that you will see a new .serverless directory in your project folder with the apollo-lambda.zip file as well as some json files).
If all went well, we should receive a message such as ‘✔ Service deployed to stack apollo-lambda-dev’ as well as our endpoints and functions (graphql).
Connecting our Apollo GraphQL to our new Server
For our final server step, we need to input the Apollo Server variables we received when we registered our schema. To do this, let’s log into our browser based AWS console and navigate to our Lambda Services (there is a search bar next to the Services tab where you can quick search Lambda).
Locate our Lambda function which should be prefixed by apollo-lambda and click on it.
We should now see our function overview. In the navigation below the function overview, locate configuration and click on it. Navigate to ‘Environment Variables’ and press the Edit button that appears. Carefully add your environment variables one at a time ensuring you capture everything to the left of the equal sign for the Enviroment Key, and everything to the right of the equal sign for the Enviroment Key Value. Once you have all 3 environment variables added, go ahead and press save to save your changes.
Connect to our GraphQL Server
With our environment variables added, let’s go ahead and visit our new GraphQL Server! Using the endpoint that was posted to our terminal, connect to your GraphQL Server. If all went well, you should be welcomed with the following screen
Finishing up with our Server
We have now successfully deployed our Apollo GraphQL Server to AWS Lambda. If you are not immediately moving on with deploying our frontend, it is always good practice to delete your AWS services to avoid any unexpected costs.
Run the following command to remove everything that we created from your AWS account (including the Cloudformation, S3 Bucket, and Lambda Function).
Please note, that if you intend on carrying on with our deployment, you should not run the following command until you have completed the project and are satisfied with the results.
npx serverless remove
Next up, deploying our React App to AWS Amplify
You are now cleared to complete your Castronaut mission in Deploying your Apollo Server! Finish out the lesson noting the differences in deploying to Heroku vs deploying to AWS Lambda. For example, one difference is that we do not need to set the PORT to deploy our server!
When your mission is complete, carry on to our next mission, Deploying Apollo Client, and check out my article on Part 2: Deploying Apollo Client to AWS Amplify.
If you found this article helpful, feel free to reach out to me on Twitter. Thanks for reading!
References
Deploying with AWS Lambda, How to deploy Apollo Server with AWS Lambda
https://www.apollographql.com/docs/apollo-server/deployment/lambda/