BillJellesmaCoding

AboutBotPalsQuick Tip Tweets

Serverless Graphql with Netlify Lambda and Apollo Angular

by Bill Jellesma
2021-04-11 15:20:00
Serverless Graphql with Netlify Lambda and Apollo Angular

Now that I have my blog built on Angular with the help of Scully, my next step was that I wanted to try out using graphql to retrieve some of my data. I knew that graphql was an alternative to REST for retrieving data from a server but I didn't know much beyond that. Fortunately, I found that Netlify offers you to get some server functionality with serverless functions by running an apollo server using AWS Lambda

Server

  1. Our first step is to install node.js and npm from nodejs.org
  2. Once nodejs and npm are installed, we can initialize a package.json file with npm init -y
  3. Now we'll install the dependencies to npm i apollo-server-lambda graphql netlify-lambda netlify-cli

apollo-server-lambda and graphql will give you the functionality to create an apollo server and to use graphql. netlify-lambda will give you the ability to serve this as if it was a netlify serverless function as well as being able to test it locally. Finally, the netlify-cli package will allow you to interact with netlify from the command line. 4. Now, we can create a file that will instruct netlify how to build the server. Create the file with touch netlify.toml. 5. Add the following to netlify.toml. This will compile all of your serverless functions to a folder called lambda

[build]
    functions = "lambda"
  1. Now, we can create a directory to house our serverless functions with mkdir functions && cd functions

  2. Create a file inside of the functions folder. touch graphql.js

  3. Use the following code inside of graphql.js

const { ApolloServer, gql } = require("apollo-server-lambda");

// Define the type definitions. Query is required
const typeDefs = gql`
  type Query {
    greeting: Greeting
  },
  type Greeting {
      friendly: String
  }
`;

// Define a greeting object that we will send to the client when they ask for it
const greeting = {
    friendly: 'Hello Bill'
  };

// Define a resolver so the greeting object is returned when greeting is queried for
const resolvers = {
  Query: {
    greeting: (root, args, context) => greeting
  }
};

// create an instance of an ApolloServer that will use the type definitions and resolvers
// also set the playground option to true so that we can use graphical when navigating to /graphql
const server = new ApolloServer({
  typeDefs,
  resolvers,
  playground: true
});

// netlify lambda expects a handler to be exported
// also set the cors to * so that we can access these resources from anywhere
exports.handler = server.createHandler({
    cors: {
        origin: '*',
    }
})
  1. Lastly for the scripting, we want to create the following scripts inside of package.json in the scripts section
"scripts": {
    "lambda-serve": "netlify-lambda serve functions",
    "lambda-build": "netlify-lambda build functions"
  },

package.json should now look like the following:

{
  "name": "graphql-server",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "lambda-serve": "netlify-lambda serve functions",
    "lambda-build": "netlify-lambda build functions"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "apollo-server-lambda": "^2.22.2",
    "graphql": "^15.5.0",
    "netlify-cli": "^3.17.0",
    "netlify-lambda": "^2.0.3"
  }
}
  1. Finally, we're ready to run the apollo server with npm run lambda-serve.

Notice that a new lambda directory will be created with a minified version of our function

If we navigate to http://localhost:9000/graphql in our browser, we'll see the graphql playground. The graphql playground is useful because it gives us an easy way to query for the resources that we defined on the server without needing to build a client. It's a sandboxed environment where we can test writing our queries and seeing if we receive the expected response.

  1. Use the following graphql in the left pane of graphical
{
  greeting {
    friendly
  }
}

and on the right pane, we'll see the expected data of the friendly greeting

{
  "data": {
    "greeting": {
      "friendly": "Hello Bill"
    }
  }
}

Graphql Playground

Client

Now, we want to make a client application that's able to retrieve these queries from the server. The goal of this client is to use angular as the frontend framework.

  1. We'll create a new angular project using ng new graphql-test.

You'll be asked for a URL for the graphql server, if you're following along with this blog post, you should be able to use our local server at http://localhost:9000/graphql.

Notice that the above ng command will create a graphql.module.ts file. This file will define a constant that is the url of our graphql server. This constant can be changed at any time.

const uri = 'http://localhost:9000/graphql'; // <-- add the URL of the GraphQL server here
  1. Create a new component to interact with graphql.

Because we have a graphql module now in addition to the normal app.module.ts, we should specify which module we want to build the component to with ng g c components/graphql-test --module=graphql.

  1. Make sure to export the GraphqlTestComponent from the graphqlmodule by adding exports: [GraphqlTestComponent] to the @NgModule decorator.
...
@NgModule({
  providers: [
    {
      provide: APOLLO_OPTIONS,
      useFactory: createApollo,
      deps: [HttpLink],
    },
  ],
  declarations: [GraphqlTestComponent],
  exports: [GraphqlTestComponent]
})
...
  1. Rewrite the graphql-test.component.ts to the following:
import {Component, OnInit} from '@angular/core';
import {Apollo, gql} from 'apollo-angular';
import { Observable } from 'rxjs';

// define the graphql query
const greetingQuery = gql`
{
  greeting {
    friendly
  }
}
`;
@Component({
  selector: 'app-graphql-test',
  templateUrl: './graphql-test.component.html',
  styleUrls: ['./graphql-test.component.css']
})
export class GraphqlTestComponent implements OnInit {
  # declare a greeting property to be an observable
  greeting: Observable<any>;

  constructor(private apollo: Apollo) {}

  # Use the watchquery method of apollo to query the graphql server
  ngOnInit() {
    this.apollo
      .watchQuery({
        query: greetingQuery,
      })
      .valueChanges.subscribe(({data, loading}) => {
        this.greeting = data?.greeting.friendly;
      });
  }
}

The watchquery method of graphql will return a data object holding the result as well as a loading object holding the state.

  1. Finally, we'll want to edit both the app.component.html and graphql-test.component.html to show our changes.

app.component.html

<app-graphql-test></app-graphql-test>

graphql-test.component.html

<div>
  {{greeting}}
</div>

If everything has worked correctly, you should see Hello Bill in your browser.