I started work at Pimp My Book in the second week of December 2018, my first task was to develop a proof of concept for our bursary division. Basically, university students were placing orders for textbooks via Google Forms and email last year in the company’s first attempt at taking this division on board. Our clients needed to see some form of improvement and also our staff needed a more automated approach to the entire process.

From the 10th of December fast forward 4 weeks into the future I managed to Deliver Zansi! A simple bare bones service that allows students to place orders for their textbooks and allows the staff at Pimp My Book the ability to see those orders come in and update their status (eg: on-order, delivered, etc) and information like which vendor has the book, its delivery date and so forth.

With that background in mind, this did not come without its troubles to get to the end goal. In the second half of 2018, I invested lot of time in my honours programme to learn GraphQL. However, I first started off using Prisma and shipped FanBoost. My overall opinion was that there are a few aspects of Prisma that would just complicate my ability to deliver Zansi on time and their support for Serverless delpoyments needed a bit more configuration. It would be doable but not ideal for the extremely short deadline hanging over my head.

Also, AWS AppSync was an option but I was extremely skeptical of the ability to implement custom business logic in their resolver mapping templates. Originally, I was under the misguided assumption that you’re not given the ability to write the resolvers in the programming language of your choice. But you are able to so in the form of Lambdas, you can also check out this post by Sarjeel Yusf that walks you through using Lambda as a data source for you AppSync service.

So I decided on Apollo-Server-Lambda on AWS lambda for my backend with a Node.JS runtime and use the Serverless Framework. While choosing React with Apollo-Client on the Front-end with a design system powered by Styled-Components.

There were several stumbling blocks that filing Github issues, emailing people and Googling just did not solve. So below are things that tripped me up, because literally I spent several days wondering how the hell people use GraphQL in serverless environments, you on the other hand do not deserve the pain and frustration I went through.

Catch 1 : Do Not Invoke It Like a REST API 😒

After creating my “Hello World” equivalent of a Serverless GraphQL API, I made the mistake of invoking it locally like so:

$ serverless invoke local -function graphql

and I would get the following error:

Do not be a wasteman like me, all you gotta do is run:

$ sls offline

then navigate to localhost:4000/name_of_endpoint in your browser and playground will open. However, you gotta make sure your serverless.yml is configured like such:

Catch 2: Authentication With Cognito On Lambda

In most cases you will need to know who your users are in your app and what they are able to access and do within your app.

One thing to note is that no matter what tool you’re using for authentication all of them can be configured to work with your GraphQL API.

This talk below helped me get an idea of the mental model needed to implement authentication for my API:

In my case, I used AWS’ Cognito service. Step 1 would be to make sure you have created userpools for your Dev and Prod environments.

Then make sure your serverless.yml for the function is configured like this:

Because you are using an AWS service, Cognito’s payload will be available in the context of your lambda so there is no extra config needed:

graphql.js

Now, how do you access your users’ attributes? Due to using the lambda_proxy integration there is a different way to access them :

If you needed to add custom attributes to your Cognito Pool you can easily add them but make sure you make them readable and writable by doing the following:

Step 1

First make sure you’ve created the custom attribute, then click App Clients

Step 2

Then click show details then “set attribute read and write permissions”

Step 3

Then tick the relevant attribute you need to be readable and writable and save the changes.

Now how do you go about testing your API in Playground? Dam good question mate🤯 !

I first had to hard code the cognito variables with dummy variables to run the function locally. This is because Serverless Offline does not work with custom authorizers. Once happy I push to Dev, then I generate a JWT from the front-end and visit my dev endpoint and paste the token in authorization header. After this, I hook up the relevant query/mutation to the front-end.

Not Ideal, but I’m yet to find a nice work around for this, please share if you have a better way avoid this crappy process!

Catch 3: Authentication With Cognito In React

On the front-end things are quite easy. You just need to install react-apollo or your preferred Apollo client library and set up an auth header for your endpoint with like so:

index.js

For your Sign up component, this is how you submit the custom Cognito attributes with Amplify:

Only issue with Amplify is that by default the users info is stored in localStorage, so a workaround needs to be investigated thoroughly for apps with stricter security requirements. I think using Cookies might be the way to go.

Catch 4: Not Understanding The Superpowers Of A ‘serverless.yml’ File

Your serverless.yml is the middleman between you and your AWS services. You should invest time in understanding how to configure this properly to be able to speak to your various services. Understanding the link between it and cloud-formation helped me overcome some of the authentication issues I faced with Cognito.

This serverless doc explores different options available to you to configure your serverless.yml in a particular way to get different API Gateway configurations.