Building my first API using Serverless, Typescript and GraphQl

Ayoub Eddakhly
Nov 27, 2018 · 7 min read

I just wanted to take a moment to thank Serverless repo maintainers for adding this project to their list of official examples. Check it out here!


Serverless is a new trend for the deployment of cloud applications. Recently it has gained much popularity mainly due to the shift of enterprise application architectures to containers and microservices.
The “serverless” term clearly does not mean that our services no longer need servers to run on(Although that would be cool 😝), but means that we no longer need provisioning of infrastructure and ongoing management of our servers, this in addition to the on-demand billing system, cuts down dramatically the cost related to compute resources.

The popularity of “serverless” as reported by Google Trends

The serverless framework is a recent development in the serverless ecosystem. It is an open-source CLI for building and deploying serverless applications, with over 6 million deployments handled to date.
Serverless is provider agnostic, so you only have to develop one version of your application to run anywhere you want it too.
So without further ado, let’s dive into some code.

Getting started with Serverless

In this tutorial, we are using :

First, let’s install Serverless framework on our machine.

npm install -g serverless
# Login to the serverless platform (optional)
serverless login

Next, let’s set up our AWS credentials.

Go to your AWS console > Security, Identity, & Compliance > IAM > Users. Create a new user with programmatic access( the one that enables an access key ID and secret access key). Click on next to set up permissions, attach existing policies and give it “administrator access”. Skip tags, and then click on “Create User”. We get a pair of keys that we have to export as environment variables on our machine so they would be accessible to Serverless and the AWS SDK in your shell.

In your terminal, enter the following:

serverless config credentials --provider aws --key YOUR_ACCESS_KEY --secret YOUR_SECRET_KEY

Creating our Boilerplate

Now that we have our environment ready let’s start by creating the boilerplate of our application.

Serverless provides a variety of examples to generate automatically, for our case we are going to use the aws/typescript one.

One thing to add, we want to be able to test our application locally before deploying it to Amazon Lambda, so we’re going to use a package that emulates serverless behavior on your machine.

sls create --template aws-nodejs-typescript
npm i
#add serverless offline
npm install serverless-offline --save-dev

We have to add serverless-offline to the list of plugins in our YAML file. It should look something like this:

(serverless.yml)
plugins:
- serverless-webpack
- serverless-offline

Now our service is ready to run and receive its first request.

$ sls offline start --port 8080

Running the previous command will get you something like this:

Starting serverless Locally

Enter http://localhost:3000/hello in your browser:

Woohoo, you just made your first serverless function.

If you look at our serverless.yml file, you’ll notice that we have a function called Hello and it’s triggered by an HTTP event.

Now let’s go ahead and integrate GraphQl…

Integrating Apollo(GraphQl)

First Install Apollos’ package for Lambda:

npm install apollo-server-lambda@rc graphql --save

Change your Handler.ts to this:

import { ApolloServer, gql } from 'apollo-server-lambda';

const typeDefs = gql`
type Query {
hello: String
}
`;

const resolvers = {
Query : {
hello: () => 'Hello world!',
}
};

const server = new ApolloServer({
typeDefs,
resolvers,
});

exports.graphqlHandler = server.createHandler();

and update serverless.yml:

service:  
name: aws-nodejs-typescript
plugins:
- serverless-webpack
- serverless-offline
provider:
name: aws
runtime: nodejs8.10
stage: ${opt:stage, 'dev'}
environment:
redisHost: '${file(./config/${self:provider.stage}.json):redis.host}' redisPort: '${file(./config/${self:provider.stage}.json):redis.port}' functions:
graphql:
handler: handler.graphqlHandler
events:
- http:
method: post
path: graphql

One more thing, in your webpack.config.js , you have to add one little change. Otherwise you’ll be flooded with errors 😆:

add ‘.mjs’ to the beginning of the extensions list

resolve: {

Our second part is now finished, we only have to test our work.

GraphQl Playground:

Awesome, now that we have GraphQl integrated, let’s set up our Database.

Running a Redis image on EC2

In the following, we are going to create an EC2 instance and start a Redis instance with Docker.

There are a lot of guides out there showing how to create an EC2 instance, so we are not going to delve into that(just make sure you choose a Linux instance, I’m choosing Ubuntu Server 18.04 LTS).

Once you got your instance ready, you want to connect to it using SSH. In the following, I am going to use Ubuntu, for windows users you can use PuTTY.

From the directory where you saved your private key file, open a terminal and run the following command.

ssh -i "keyName.pem" your_instance_host
Connect to the EC2 instance

Then install Docker:

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
$ sudo apt-get update
$ apt-cache policy docker-ce
$ sudo apt-get install -y docker-ce

Docker is now installed, the daemon started, and the process enabled to start on boot. Check that it’s running:

$ sudo systemctl status docker
Docker running on EC2

Let’s run a Redis image:

$ docker run --volume /docker/redis-data:/data -p 6379:6379 -d redis   redis-server --appendonly yes
Redis Image on Docker

Let’s check it:

$ sudo docker container ls
Redis Running on EC2

Finally, let’s start working on our API.

Building our API

Handler.ts:

To begin, let’s import Apollo Server for Lambda:

import { ApolloServer, gql } from 'apollo-server-lambda';

Next, we define our queries and mutations. We are going to create a commenting service; hence we have a “Comment” type.

const typeDefs = gql`
type Comment{
msgId: Int
userId : String
content : String
createdAt : String
deleted : Boolean
}
type Query {
get(itemId: String): [Comment]
}
type Mutation {
add(itemId: String, userId:String, content:String): [Comment]
edit(itemId: String, msgId:Int,userId:String, content:String): [Comment]
delete(itemId: String, msgId:Int, userId:String) : [Comment]
}
`;

The last thing is our resolvers:

const resolvers = {
Query: {
get: (root, args) => {
//get from comment service
},
},
Mutation: {
add: (roots, args) => {
//add from comment service
},
edit: (roots, args) => {
//edit from comment service
},
delete: (roots, args) => {
//delete from comment service
}
}
};e

Before creating our commenting service, let’s create a service that connects to the Redis database(comment.storage.ts).

Let’s install Redis

npm i redis --save

Add a file called types.ts to the root of your project:

then comment.storage.ts:

Now let’s implement our comment.service.ts:

It doesn’t have much, but this service is going to be useful if we want to add some logic and filtering.

Return to our Handler.ts. We are going to implement the missing functions:

Now our logic is complete, all we have to do is configure Redis port and host.

Let’s create a config folder, inside create a prod.json, u can create later a file for every stage(maybe one for a local development environment with a local Redis instance), we’re going to see how to configure that in our serverless.yml.

(prod.json)

ps: ec2–a–b–c–d.ec2_region.compute.amazonaws.com then your IP is a.b.c.d

otherwise just check it out on the aws console.

Check the connection to your Redis database.

$ sudo apt-get install redis-tools

then test the connection:

Change your serverless.yml, so it can grab the specific configuration file when stage changes.

Fire up your local serverless function

sls offline start

and test your functions:

Feel free to test the other functions as you wish.

Our app is now done 😎 ! Let’s deploy it.

ps: if you face an error like this one

Module not found: Error: Can't resolve 'hiredis'...

Create a folder named “aliases” at the root of your project, within this folder create a file hiredis.js with the following content:

export default null

and then add this to your webpack.config.js:

extensions: .............................,

Deploying to AWS Lambda

Were you afraid of the deployment? Let me show you how easy it is to deploy your app with Serverless.

Literally, all you have to do is type this in your terminal:

sls deploy -v --stage prod

Grab the endpoint and test your service.

Check out the Github Repo here!

Thanks for reading !

If there is anything I have missed please let me know. If you have a better way of writing any of the code above submit a pull request on Github.

Find me on LinkedIn and follow me for more.

ps: looking for an internship, hit me up 😉

Ayoub Eddakhly

Written by

Computer Science Student | Software Architect Wanna Be | passionate about building stuff, learning new things and sharing knowledge.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade