GraphQL is gaining fast in popularity due to its power to define crisp APIs asking for exactly what is needed. This query language gives clients the power and flexibility to control the data needed, making it easier to design the APIs incrementally and improve performance by limiting to only the required data elements. It provides the clean layer of abstraction between servers and clients compared to an ad-hoc REST approach and brings greater control as well as clarity.
GraphQL is definitely the way ahead and in this blog, we will see how we can make use of the power of GraphQL specifications to work together with Angular (6) and PostgreSQL and enable us to build high-performance applications.
Step 1 – Setup the database and schema
We will set up our Postgresql database using Elephantsql.com or local pg. Create the schema and table in the database. We will be designing an Angular page to display the employee data from the below schema by inserting some sample data.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
CREATE SCHEMA WTT; CREATE TABLE wtt.employee ( employee_id integer NOT NULL, firstname character varying(200) NOT NULL, lastname character varying(200) NOT NULL, email character varying(150) NOT NULL, isactive character(1) DEFAULT 'Y'::bpchar NOT NULL, isreference character(1) DEFAULT 'N'::bpchar NOT NULL, created timestamp without time zone DEFAULT now() NOT NULL, createdby integer NOT NULL, updated timestamp without time zone DEFAULT now() NOT NULL, updatedby integer NOT NULL ); |
Step 2 – Create a new angular application using cli.
1 2 |
ng new ng-gql-pg cd ng-gql-pg |
Now we will work on the server part and come back to modify this angular application later.
Step 3 – Setup Graphql server
Create a new server.js file inside the application folder for including the server code.
There are three types of operations that GraphQL models:
- query – a read-only fetch. Equivalent to a regular GET(REST) or SELECT(SQL) or FIND(NOSQL)
- mutation – a write followed by a fetch. Equivalent to POST, PUT, PATCH and DELETE in REST or Insert/Update/Delete followed by query
- subscription – a long-lived request that fetches data in response to source events.
In this blog, we will be implementing the query operation.
In order to get started with Graphql, below are the steps needed to setup Graphql and define an endpoint served by the Graphql server.
Using Node+Express+Graphql
- We will first install the prerequisites.
1 |
npm install express, express-graphql, graphql, cors --save |
- Next, we define the schema- This is critical in stating exactly what we expect from the server. GraphQL Interface Definition Language code is used to describe the schema. The schema is used to describe the complete set of data and define how the data can be accessed. Each time the client makes an API call, the call is validated against the schema. Only if the validation is successful the action is executed. Otherwise, an error is returned. This is the first level of validation for the API call.
- In our example, we will query for the employee details comprising of first name and last name
1 2 3 4 5 6 |
const schema = buildSchema(` type Query { firstname: String, lastname: String } `); |
- Define the resolver for the queries. In the simplest form, our code can hardcode and resolve the values as below.
1 2 3 4 |
const root = { firstname: () => 'Walking', lastname: () => 'Tree' }; |
- Using express, we create an express server and using express-graphql, we will define the GraphQL endpoint on this server.
- The first parameter is the URL endpoint, given as a string which identifies the endpoint
- The second parameter is the result of the express_graphql function call by passing a configuration object with the following three properties
- schema: The GraphQL schema which should be attached to the specific endpoint. This will contain the queries and mutations handled by this endpoint.
- rootValue: The root resolver object, which will have the resolver logic to handle the different operations given in schema
- graphiql: This is set to true to enable the GraphiQL tool when accessing the endpoint in the browser. GraphiQL is a graphical interactive in-browser GraphQL IDE using which you can directly write your queries in the browser and try out the endpoint.
Let’s see the complete code for the above step.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
const express = require('express'); const express_graphql = require('express-graphql'); const { buildSchema } = require('graphql'); const cors= require('cors'); // GraphQL schema to define the operations with types of data elements involved const schema = buildSchema(` type Query { firstname: String, lastname: String } `); // Resolver logic to respond to the query const root = { firstname: () => 'Walking', lastname: () => 'Tree' }; // Create an express server and a GraphQL endpoint const app = express().use('*', cors());//cors included to enable CORS requests app.use('/graphql', express_graphql({ schema: schema, rootValue: root, graphiql: true })); app.listen(4000, () => console.log('Express GraphQL Server Now Running On localhost:4000/graphql')); |
Now we run our server code using nodemon (to continue monitoring changes):
1 |
nodemon server.js |
We can now launch our server at http://localhost:4000/graphql and query as below.
1 2 3 |
{ firstname } |
The output will show as:
1 2 3 4 5 |
{ "data": { "firstname": "Walking" } } |
This simple query which returns static data will help understand how schema and resolver work together to give the response from the server.
Note: CORS option is enabled for all requests on the server using cors. If not included, this results in the error “No ‘Access-Control-Allow-Origin’ header is present on the requested resource.” when trying to get data from the server to the client browser.
Now we will see how we can improvise on the above query and connect it to our Postgresql database.
Step 4 – Setup Postgresql database connection and resolver
Using Pg-promise:
1 |
npm install pg-promise --save |
Include connection details in server.js.
1 2 3 4 5 6 7 |
//pg connection details const pgPromise = require('pg-promise'); // add your Postgresql connection string details const connStr = 'postgres://imrlsisb:mpJx2ZCqroGCcKmJGY_j_KddOTgiKyka@stampy.db.elephantsql.com:5432/imrlsisb'; const pgp = pgPromise({}); // empty pgPromise instance const psql = pgp(connStr); // get connection to your PG db instance |
Modify the schema to include the details of employee schema:
1 2 3 4 5 6 7 8 9 10 11 |
var schema = buildSchema(` type Query { allEmployees: [Employee] employee(employee_id: Int!): Employee }, type Employee { employee_id: Int firstname: String lastname: String } `); |
Modify the resolver to fetch data from the database as below:
1 2 3 4 5 6 7 8 9 10 11 |
root= { employee : async ({ employee_id }) => { const empQuery = 'select employee_id, firstname, lastname from wtt.employee where employee_id=' + employee_id ; return psql.oneOrNone(empQuery);//using pgsql connection to get data }, allEmployees : async (parent, args, ctx) => { const empQuery = 'select employee_id, firstname, lastname from wtt.employee'; return psql.manyOrNone(empQuery);//using pgsql connection to get data }, }; |
Now the Graphql server is ready to fetch data from the Postgresql database. (Since we used nodemon, we don’t need to rerun the server as it automatically detects changes)
Run the queries on your graphiql (http://localhost:4000/graphql) and see the response as below for all employees.
For the specific employee:
The query schema and resolver can be further modified as per the data requirements and the server.js file will be split up into separate files for schema and resolver as the application grows in size and complexity.
The next step is to consume this data in the Angular client. We will do this using Apollo-angular, the Apollo-client for Angular.
Step 5 – Install Apollo-angular and other prerequisites.
1 2 |
npm install apollo-angular apollo-angular-link-http apollo-client apollo-cache-inmemory graphql-tag primeng primeicons --save |
Step 6 – Modify the Angular application
The next step is to import the required dependencies in AppModule which will be required to set up the Apollo client:
-
- ApolloModule: the main module for Apollo Client’s features
-
- HttpLinkModule: the module used to fetch data in Angular
-
- HttpClientModule: HttpLinkModule uses the HttpClient internally in order to make HTTP calls, hence needs to be imported.
-
- Apollo service and the HTTP link service: to be included as part of imports to make use of these services
- InMemoryCache : To enable in-memory caching.
1 2 3 4 |
import { HttpClientModule } from '@angular/common/http'; import { ApolloModule, Apollo } from 'apollo-angular';//imports for apollo-angular import { HttpLinkModule, HttpLink } from 'apollo-angular-link-http';//imports for apollo-angular import { InMemoryCache } from 'apollo-cache-inmemory'; |
In order to create an Apollo client connection, first, we will inject both services into the constructor of class AppModule using dependency injection to have a single instance of the service available for the entire application
1 2 |
class AppModule { constructor(apollo: Apollo,httpLink: HttpLink) { } |
Next, we create the Apollo Client connection to our GraphQL server by using the following code, providing the URL of the server created in earlier steps, within the constructor:
1 2 3 4 |
apollo.create({ link: httpLink.create({uri: 'http://localhost:4000/graphql'}), cache: new InMemoryCache() }); |
Note: You may encounter the following error on this inclusion.
1 2 3 4 |
<em>ERROR in node_modules/@types/graphql/subscription/subscribe.d.ts(17,12): error TS2304: Cannot find name 'AsyncIterator'. node_modules/@types/graphql/subscription/subscribe.d.ts(29,12): error TS2304: Cannot find name 'AsyncIterable'.</em> |
This can be rectified by including the lib option in compilerOptions provided in tsconfig.app.json(tsconfig.json):
1 2 3 4 5 |
"lib": [ "es2017", "dom", "esnext.asynciterable" ] |
Now run your angular application to make sure it is working fine. Next, we will include the logic to get data from the graphql server and display in a grid using primeng p-table.
Added a new employeeGrid component and included below code in employeeGrid.component.ts to consume the data by making a call to the graphql server.
Include the required imports.
1 2 3 4 |
import { Apollo } from 'apollo-angular'; import { Subscription} from 'rxjs'; import gql from 'graphql-tag'; import {Employee, allEmployees} from '../shared/employee.interface';//types for the employee object |
Create an instance of Subscription and Employee[]. Inject the instance of Apollo client through the constructor.
1 2 3 4 |
emp: Employee[]; empSubscription: Subscription; constructor(private apollo: Apollo) { } |
Now in ngOnInit hook, we invoke the watchQuery method and send the graphql query using gql and subscribe to the response as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
this.empSubscription = this.apollo.watchQuery<allEmployees>({ query: gql` query allEmployees{ allEmployees { employee_id firstname lastname } } ` }).valueChanges .subscribe(({ data, loading }) => { this.emp = data.allEmployees; }); } |
Don’t forget to unsubscribe in ngOnDestroy. The output looks like below with some formatting applied using primeng. You can check the complete code here.
Summary
This blog gives a basic idea of getting started with Graphql in angular applications with Postgresql database. Now you can build more powerful Angular applications utilizing the prowess of GraphQL and Postgresql.
References:
- http://facebook.github.io/graphql/
- https://building.buildkite.com/tutorial-getting-started-with-graphql-queries-and-mutations-11211dfe5d64
- https://blog.apollographql.com/tutorial-building-a-graphql-server-cddaa023c035
- https://www.apollographql.com/docs/angular/basics/queries.html#basics
- https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18557
Hey,
Thanks for the tuturial, it was very helpful.
However I am stuck now at step 6
import {Employee, allEmployees} from ‘../shared/employee.interface’;//types for the employee object
Where do I find the employee.interface?