Description
GrahpQL [1] means Graph Query Syntax and describes a „protocol“ for your data transfer.
Motivation
Negotiation to an API, an interface between frontend and backend is time-critical. Often both is developed in parallel and the result gets „hacked“ to fit. But a first common data scheme can help.
A good practice for REST-APIs is to choose Swagger [2], so you end up in a well known relational database „create, read, update, delete“-scenario for example.
A modern opponent is a graph API where also most likely a graph database is involved in the backend (to not have an overhead of bending technologies to fit).
So now, to get a setup with Angular and GraphQL, there is already a well evolved library called Apollo Client [3]. Mind the „Simple to get started with“, which is important to not loose the focus in details.
Setup
Via Angular Schematics: ng add apollo-angular
Initial Sample
app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { MainPageComponent } from './main-page/main-page.component'; import { FormsModule } from '@angular/forms'; import { GraphQLModule } from './graphql.module'; import { HttpClientModule } from '@angular/common/http'; @NgModule({ declarations: [MainPageComponent], imports: [ BrowserModule, AppRoutingModule, FormsModule, NgbModule, GraphQLModule, HttpClientModule, BrowserModule, HttpClientModule, ], providers: [], bootstrap: [MainPageComponent], }) export class AppModule {}
graph.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { MainPageComponent } from './main-page/main-page.component'; import { GraphQLModule } from './graphql.module'; import { HttpClientModule } from '@angular/common/http'; @NgModule({ declarations: [MainPageComponent], imports: [ BrowserModule, AppRoutingModule, GraphQLModule, HttpClientModule, ], providers: [], bootstrap: [MainPageComponent], }) export class AppModule {}
main-page.component.html
<div class="container"> <h2>Rates</h2> <ul class="list-group"> <li *ngFor="let rate of rates | async" class="list-group-item"> {{rate.currency}}: {{rate.rate}} </li> </ul>
main-page.component.ts
import { Component, OnInit } from '@angular/core'; import gql from 'graphql-tag'; import { Apollo } from 'apollo-angular'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; const GET_RATES = gql` { rates(currency: "USD") { currency rate } } `; @Component({ selector: 'app-main-page', templateUrl: './main-page.component.html', styleUrls: ['./main-page.component.scss'], }) export class MainPageComponent implements OnInit { rates: Observable<any>; constructor(private apollo: Apollo) {} ngOnInit() { this.rates = this.apollo .watchQuery({ query: GET_RATES, }) .valueChanges.pipe(map((result) => result.data.rates)); } }
Observations
- graphql.module.ts is a new Angular Module, configuring the data source
- gql`…`; contains the raw query
- the apollo client starts this query asynchronously
- the resulting data is transformed via a pipeline, which is a common pattern for handling async data, here we get support by the libary rxjs [4]
- currently „result.data.rates“ contains a call to an unkown type, whereas our query actually delivers the data scheme, but probably doesnt spit out a typescript type yet, which would deliver us autocompletion
- obviously coding contains a lot of „adapt and combine existing solutions“
References
[1] https://graphql.org/learn/
[2] https://swagger.io/resources/articles/best-practices-in-api-design/
[3] https://www.apollographql.com/docs/angular/
[4] http://reactivex.io/rxjs/manual/overview.html