DEV Community

Tanja Bayer for Cubesoft GmbH

Posted on

Setting Up your Apollo Server with TypeGraphQL

Welcome back to the second part of the Zero to Serverless Hero Series. In this blog post I will cover how you can configure your lambda to handle GraphQL queries.

If you are not yet familiar with how GraphQL works, I would recommend you to read the GraphQL Documentation.

Getting Started

For implementing the GraphQL schemas we will be using TypeGraphQL because this gives us an easy to understand and maintainable way to implement the GraphQL schema by using decorators. As of the time of writing the support for Apollo v4 version is still in beta, nevertheless, we will use the beta, because Apollo v3 is already deprecated. So let’s install it, along with the aws-lambda package which we will need npm i type-graphql@2.0.0-beta.1 aws-lambda. For building and deploying the lambda we will additionally install the following package as dev dependencies: npm i -D @cubesoft/nx-lambda-build depcheck.

Creating the Lambda Handler

In the last blog post we used inline code for our lambda handler. However, that should be only done only for testing or if you have pretty small functions, because you loose a lot of code maintainability there. So first we will put our lambda code into a separate file called serverless-api.ts.


 typescript
import { APIGatewayProxyEventV2, Context } from 'aws-lambda';

export async function handler(event: APIGatewayProxyEventV2, context: Context) {
  console.log('Hello, CDK!');
  return {
    statusCode: 200,
    body: JSON.stringify('Hello from Lambda!'),
  };
}


Enter fullscreen mode Exit fullscreen mode

Then we need to tell the cdk how to find the code. Therefore, we need to change the lambda part in our stack (serverless-stack.ts):


 typescript
const lambda = new Function(this, 'api-handler', {
  runtime: Runtime.NODEJS_18_X,
  handler: 'serverless-api.handler',
  functionName: 'serverless-api',
  code: Code.fromAsset(
    join(
      getWorkspaceRoot(),
      'dist/packages/serverless-api/serverless-api',
      'handler.zip'
    )
  ),
  memorySize: Size.gibibytes(1).toMebibytes(),
  architecture: Architecture.ARM_64,
  logRetention: RetentionDays.ONE_DAY,
  timeout: Duration.seconds(5),
});


Enter fullscreen mode Exit fullscreen mode

Additionally we also need to tell the nx-lambda-build plugin where our handler will be located. Therefore, we need to create a file called serverless-api/src/handlers.json to create a mapping between the handler name and the code location:



{
  "entrypoints": {
    "serverless-api": "src/handler/serverless-api"
  }
}


Enter fullscreen mode Exit fullscreen mode

Before updating our lambda to be able to function as a GraphQL server, we first want to check if what we did so far is functioning. Because it is much easier to test smaller changes and fixing errors right after they occur, instead of searching for the problem in a whole stack of changes. For testing our lambda we first need to build it and then deploy it:


 bash
nx build serverless-api 
nx deploy serverless-cdk --profile <your-profile>


Enter fullscreen mode Exit fullscreen mode

You need to confirm that you want to deploy the changes and afterwards you can check, that your /graphql endpoint still returns "Hello from Lambda!". If you go to your AWS Console and open your lambda function (Lambda > Functions > serverless-api), you will also see that your code is now deployed:

AWS Lambda Console View

Configuring the Apollo Server

We need to install some dependency for using the Apollo server npm i -S typedi reflect-metadata @apollo/server graphql reflect-metadata @as-integrations/aws-lambda. After installing these dependencies we can start creating our first resolver, which we can later pass to our Apollo Server, which we will create in the next step.

We will stick with our easy lambda example and for the beginning and start with an easy query that will just return a message.


 typescript
import { Query, Resolver } from 'type-graphql';
import { Service } from 'typedi';

@Service()
@Resolver()
export class GreetingResolver {
  @Query(() => String, {
    description:
      'Returns a greeting message. This is a sample query that returns a string',
  })
  async hello(): Promise<string> {
    return 'world';
  }
}


Enter fullscreen mode Exit fullscreen mode

Make sure to add both the @Resolver and the @Query decorator to your class. The @Resolver class is TypeGraphQL specific and is required to build the GraphQL schema from your implementation. The @Query decorator marks the class method as a GraphQL query.

After we have created our resolver we can create the Apollo Server and a build a GraphQL schema including our resolver. For this we replace the content of our serverless.api.ts file with the following code.


 typescript
import 'reflect-metadata';
import { ApolloServer } from '@apollo/server';
import 'graphql';
import { buildSchemaSync } from 'type-graphql';
import {
  handlers,
  startServerAndCreateLambdaHandler,
} from '@as-integrations/aws-lambda';
import { GreetingResolver } from '../resolver/greeting.resolver';

const schema = buildSchemaSync({
  resolvers: [GreetingResolver],
  validate: { forbidUnknownValues: false },
  dateScalarMode: 'timestamp',
});

const server = new ApolloServer({
  schema: schema,
  introspection: true,
  csrfPrevention: true,
});

export const handler = startServerAndCreateLambdaHandler(
  server,
  handlers.createAPIGatewayProxyEventV2RequestHandler()
);


Enter fullscreen mode Exit fullscreen mode

As you can see we tell our schema to use our newly created resolver. Afterward this schema is injected into the Apollo Server and as a last part we create the handler to tell our lambda how to execute our calls.

Deploy your stack

Finally, you can build and deploy your CDK stack using the command nx build serverless-api && nx deploy serverless-cdk --profile serverless-hero. If you open your browser this time using the same url as last time (/graphql) you will no longer see the message "Hello from Lambda!" but you will see the apollo playground like in the image below. Now you have a GraphQL lambda hander, it only supports one simple query but this is a good starting point, isn’t it?

Apollo Playground

Next time we will setup a database for storing and retrieving data for your application.

You can find my sample repo here

Top comments (0)