Serverless GraphQL api using cga cli

Tom Yitav
Castory-ai
Published in
5 min readJan 26, 2019

--

Create production-ready GraphQL api in serverless environment

Background

create-graphql-app is a cli tool, designed to make it easy to develop and deploy a Serverless GraphQL api. In this post, we will create a new NodeJS api from scratch, and deploy it to production in a matter of minutes.

As we will see, cga cli bootstraps a boilerplate project for us, that is set with useful GraphQL related features. The project will be set for one of two Serverless deployment alternatives- aws-lambda, or now-cli

The rationale for using the CLI is to cut some of the more tedious repetitive jobs in developing a GraphQL backend.

TL;DR

  • Watch tutorial video on YouTube
cga overview and usage tutorial

Prerequisites

  • NodeJS version 8+ installed
  • Basic understanding of GrapQL concepts. (Schema, Resolver, etc.)

CLI commands overview

Installation

npm install -g create-graphql-app

Initializing the server

In order to create a new server project, we’ll use the init command as follows:

cga init <project-name>

We shall create a new project call hello-gql, so we should run

cga init hello-gql

The command will open the following prompt:

init command prompt

There are two boilerplates project that we can start from. The first will set up a now deployment project, and the second is setting up aws-lambda configuration.

Both seed projects set up multiple enterprise grade features, such as creating a modular schema, use of Dependency Injection, Typescript code generation, and more!

Further explanations about the starter project structure are available in the following post

We will select the first option. The seed project will be cloned, and its dependency libraries will be installed for us.

Running the server locally

To build the project, we’ll run

npm run build

or on Windows machines:

npm run build:win

This will trigger two things- Typescript types generation, and Typescript transpilation to javascript. The transpiled output is in the dist directory. Running

npm start

Will spin up the server. We can open graphql playground on http://localhost:8080/graphql

Basic gql Query in playground

Adding new entity

Let’s say we want to add a new entity to our api, called station. As we have seen in the seed project overview above, our schema is splitted to multiple files. We’ll add a new station.ts file to types directory, with the following content

const schema = `
type Station {
_id : String
name: String
}

# the schema allows the following query:
type Query {
station(name: String): [Station]
}

type Mutation {
updateStationName(_id: String!, newStation: String!): Station
}

type Subscription {
stationChanged: Station
}
`

export default schema

We can build the server again- and the new Typescript definitions will be generated for us.

Generate matching resolver file

We now need to provide resolver definitions for the schema file we have created. This is easily done with the resolver generation command

cga r <type-file> <resolver file>

This will create a matching file, with all the Query, Mutation and Subscription definitions.

We shall open a cmd in the directory of station.ts schema file, and execute

cga r station.ts ..\resolvers\station.ts

This will create a resolver file to the reserved resolvers directory. The project will merge the resolver implementation for us by using the merge-graphql-schemas library. The file will now hold the following definitions:

import {IAppContext} from '@src/interfaces/IAppContext'const resolveFunctions = {
Query: {
station(rootObj: any, args: any, context: IAppContext) {
}
},
Mutation: {
updateStationName(rootObj: any, args: any, context: IAppContext) {
}
},
Subscription: {
stationChanged: {
subscribe: (rootObj: any, args: any, context: IAppContext) => {
}
}
}
}
export default resolveFunctions

No need to manually state these definitions ourself. We will provide resolvers implementation later on.

Implementing business logic with services

Our server resolvers should operate as a thin layer, or controller, that links between the schema, and the server business logic. We use services for our model, to perform logic such as api fetching, db operations, etc. In order to create a new service, we run the command:

cga s <service-path> [--ignoreContext]

This will create a new service file to services directory. Also, it will register the service on the server injector file, and will add its definition to the context object, thus allowing its usage by resolvers. You can exclude context file additions by passing the ignoreContext flag.

Let’s implement the stations fetching logic in a new service. In the project root directory, we run

cga s station.ts

We now have a new station.ts file in our services directory, with the following content

import {Injectable} from 'injection-js'

@Injectable()
export class StationService {
}

Apart from creating this file, we have registered the service on the server’s injector file, and on the application context definitions. This will allow us to use the service from our resolvers. We will simulate fetching by returning a simple promise. we will add the content to the service file:

import {Injectable} from 'injection-js'
import {AbstractLogger} from '@src/core/logger/AbstractLogger'
import {Station} from '@src/interfaces/types'

@Injectable()
export class StationService {


constructor(private logger: AbstractLogger) {
}

public getStations(name: string): Promise<Station[]> {
this.logger.info('Return all stations...')

return new Promise<Station[]>((res) => {
res([{
_id: "1",
name: "station1"
}])
})
}
}

Note: The Station type we used, was previously generated by graphql-code-generator during the build phase.

We can now use the service from the resolver file. Let’s update our query body:

Query: {
station(rootObj: any, args: StationQueryArgs, context: IAppContext): Promise<Station[]> {
return context.stationService.getStations(args.name)
}
},

We can build the server again and verify in the playground that the query works

Running the station query in playground

Deploy to production 🚀

We are now ready to deploy our server to production! In order to do that, we must have the now-cli installed.

Inside the project directory, type:

cga d

This will run the server deploy script, and will move the server to production!

Conclusion

In this post, we have seen how easy it is to create a GraphQL api using create-graphql-app cli. The cli can help us eliminate writing some of the boilerplate code manually.

I hope you have enjoyed reading the post, and found the library helpful in implementing a serverless api in your own systems.

If you liked the post, please feel free to waste a few seconds to give it 50 claps :-)

--

--

Tom Yitav
Castory-ai

Experienced software developer, passionate about creating new things