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
npm init -y
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"
Now, we can create a directory to house our serverless functions with mkdir functions && cd functions
Create a file inside of the functions folder. touch graphql.js
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: '*',
}
})
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"
}
}
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.
{
greeting {
friendly
}
}
and on the right pane, we'll see the expected data of the friendly greeting
{
"data": {
"greeting": {
"friendly": "Hello Bill"
}
}
}
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.
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
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
.
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]
})
...
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.
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.