In this article, we will learn about consuming GraphQL API from angular applications using the Apollo Angular library.
src/app/app.component.html:
Overview On GraphQL API:
As a front-end developer, no need to understand about in-depth nature of the GraphQL API. But it will be good to know about few key features about it for development.
GraphQL API mostly has a single endpoint. So data fetching or updating will be carried out by that single endpoint. For posting data or querying data, we have to follow its own syntax. GraphQL carries two important operations:
- Query - fetching data
- Mutation - updating or saving data.
Create A Sample Angular Application:
Let's create a sample angular application where we are going to implement techniques to consume the GraphQL endpoint.
Command To Install Angular CLI:(If not installed on your system previously)
npm install -g @angular/cli
Angular CLI Command To Create Angular App: ng new your_project_name
Command To Run App:
ng serve
Install Apollo Angular Library:
Apollo Angular provides us an easy way to install and configure it into our application with a simple 'ng' command below.
Command To Install And Setup Apollo Angular :
ng add apollo-angular
The command installs 3 different libraries like 'apollo-angular', '@apollo/client', 'graphql'.The 'graphql.module.ts' a new file will be created with all startup configurations regarding GraphQL.Configure GraphQL Endpoint:
For this demo, I have developed a sample GraphQL endpoint that I will use in our angular sample application.
In the 'graphql.module.ts' file constant variable 'uri', we need to assign our GraphQL endpoint value.
src/app/graphql.module.ts:
GraphQL Query Syntax:
In GraphQL, the Query represents the fetching of the data. The sample syntax of the query looks as below.
Query Syntax:
query{ MyGadgets{ Id, ProductName, Brand } }
- 'query' keyword to understand the request type.
- 'MyGadgets' will be the method name on the server.
- The 'Id', 'ProductName', 'Brand' are properties to be returned in the response data. The beauty of GraphQL is to fetch only required props. For suppose if we need only 'ProductName' then we can pass only that property in the request so that response will contain only 'ProductName'.
Consume Basic Query:
The above tool(generated by the server application) is very helpful to test the GraphQL endpoint by all the developers. From the pic, we can see the GraphQL query and response. Now here we are going to prepare the same query in our angular application and then invoke the endpoint and then capture the response.Let's create an interface type for the response model. So let's create a folder like 'models' and then add a file like 'gadget.ts'
models/gadget.ts:
export interface Gadget { Id:number, ProductName:string, Brand:string, Cost:number, Type:string }Now update our 'app.component.ts' with the following logic.
src/app/app.componen.ts:
import { Component, OnInit } from '@angular/core'; import {gql, Apollo} from 'apollo-angular'; import { Gadget } from './models/gadget'; const Get_MyGadgets = gql` query{ MyGadgets{ Id, ProductName, Brand, } } `; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { allGadets:Gadget[] = []; constructor(private apollo: Apollo){} ngOnInit(): void { this.apollo.watchQuery<any>({ query: Get_MyGadgets }) .valueChanges .subscribe(({data, loading}) => { console.log(loading); this.allGadets = data.MyGadgets; }) } }
- (Line 2) Importing few instances from the 'apollo-angular' library.
- (Line: 5-13) Assigned our query as a constant value. We have prefixed 'gql' to our query, 'gql' parse our string GraphQL query to the GraphQL document.
- (Line: 22) Injecting 'Apollo' constructor.
- (Line: 24-31) Invoking GraphQL endpoint and subscribing to the response. The 'watchQuery' method from the 'Apollo' instance returns 'valueChanges' which is observable. To capture the response data we have to subscribe to it. Subscriber reads object that contains properties like 'data' and 'loading'. The 'data' property contains responses from the GraphQL server. The 'loading' property returns a boolean value to represent the completion of the API call.
src/app/app.component.html:
<table class="table table-dark table-striped"> <thead> <tr> <th scope="col">Id</th> <th scope="col">Product Name</th> <th scope="col">Brand</th> <th scope="col">Cost</th> <th scope="col">Type</th> </tr> </thead> <tbody> <tr *ngFor="let gadget of allGadets"> <td>{{gadget.Id}}</td> <td>{{gadget.ProductName}}</td> <td>{{gadget.Brand}}</td> <td>{{gadget.Cost}}</td> <td>{{gadget.Type}}</td> </tr> </tbody> </table>One final step is to import the 'FormModule' from '@angular/form' into the 'app.module.ts'.
Now start the application and checks the output of our sample.
Filters In GraphQL Query:
We can have filters in GraphQL Query. The filters are nothing but the query params or user payload.
Query Syntax:
query ($brandName:String){ BrandFilter(brand:$brandName){ Id, ProductName, Brand } }Variable Syntax:
{ "brandName":"Samsung" }Usually, query parameters or payload is dynamic data passed by the users. So appropriate way to pass the query data into GraphQL query is to use GraphQL Variables. In 'Variable' object property name 'brandName' should match with '$brandName' in the GraphQL Query. The ($bradName:String) means defining the type for the variable. The 'brand' is the input parameter for the 'BrandFilter' function inside of the server. So to pass the variable data we will assign '$brandName' to 'brand' in 'BrandFilter'.
Consume Query With Filters:
Upgrade our sample application to use a GraphQL Query with filter data. So that we will create a search bar where we will filter data by the gadget's brand name.
src/app/app.component.ts:
import { Component, OnInit } from '@angular/core'; import {gql, Apollo} from 'apollo-angular'; import { Gadget } from './models/gadget'; const Get_BrandFilter = gql` query ($brand:String){ BrandFilter(brand:$brand){ Id, ProductName, Brand } }`; // Some code hidden for display purpose @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { allGadets:Gadget[] = []; selectedBrand:string = ''; searchByBrand(){ this.apollo.watchQuery<any>({ query: Get_BrandFilter, variables:{ brand: this.selectedBrand } }) .valueChanges .subscribe(({data, loading}) => { console.log(loading); this.allGadets = data.BrandFilter; }); } }
- (Line: 5-12) GraphQL Query with filtering capability had declared as a constant.
- (Line: 23) The 'selectedBrand' variable will be used to store the user-entered brand name to filter the data.
- (Line: 26-38) The 'searchByBrand' method to invoke GraphQL endpoint with the filtered data. Here we can observe user-entered data passed to the 'variables' object.
src/app/app.component.ts:
<form class="row g-3"> <div class="col-auto"> <label for="txtSearch" class="visually-hidden">Search By Brand</label> <input type="text" [(ngModel)]="selectedBrand" name="txtSearch" class="form-control" id="txtSearch" placeholder="Search By Brand"> </div> <div class="col-auto"> <button type="submit" class="btn btn-primary mb-3" (click)="searchByBrand()">Search</button> </div> </form>
- (Line: 4) Text field enabled model binding where we are going to capture the data entered into the 'selectedBrand' variable.
- (Line: 7) Button click event register with method 'searchByBrand'.
GraphQL Mutation:
The mutation is meant to change the state of the data like creating or updating a record.
Mutation Syntax:
mutation ($inputType:GadgetsInput ){ Save(gadgetInput:$inputType) { Id, ProductName, Brand, Cost, Type } }Variable Syntax:
{ "inputType":{ "ProductName":"Think Pad 2.0", "Brand":"Samsung", "Cost":7500, "Type": "Laptop" } }
- The 'mutation' keyword determines GraphQL type.
- The '$inputType' name should match with the 'variable' parent object property name like 'inputType'.
- The '$inputType' type is defined as 'GadgetsInput' this name should match with the server-side class name.
- The 'Save' method is the sever method where it contains logic to add a new record to the database.
- We have defined properties to be returned as the response to the newly created object. In the sample above we are requesting all the properties of the newly created record.
Consume Mutation:
Now from our sample, we are going to invoke GraphL Mutation to create a new record.
src/app/app.component.ts:
import { Component, OnInit } from '@angular/core'; import {gql, Apollo} from 'apollo-angular'; import { Gadget } from './models/gadget'; // some existing code hidden for display purpose const Post_Save = gql `mutation ($inputType:GadgetsInput ){ Save(gadgetInput:$inputType) { Id, ProductName, Brand, Cost, Type } }` @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { allGadets:Gadget[] = []; selectedBrand:string = ''; gadgetForms = { Brand:'', Cost:0, ProductName:'', Type:'' }; newGadget(){ this.apollo.mutate({ mutation:Post_Save, variables:{ inputType:{ ProductName: this.gadgetForms.ProductName, Brand: this.gadgetForms.Brand, Cost: Number(this.gadgetForms.Cost), Type: this.gadgetForms.Type } } }).subscribe(({data}) => { let gadgets = Object.assign([], this.allGadets) gadgets.unshift(data["Save"]); this.allGadets = gadgets; }) } }
- (Line: 7-15) Mutation string constant
- (Line: 25-30) The 'gadgetForms' object used for model binding of data from the form.
- (Line: 31-47) GraphQL mutation call invoking. Here now we are using 'mutate' method from the 'Apollo' instance. We passing our 'Post_Save' constant value to the 'mutation' property. Inside of the 'variable' property we have created a property 'inputType' this should name must match with '$inputType' inside of 'Post_Save' constant. Our payload needs to be assigned to the 'inputType' property. On a successful response, we are updating the newly created record into our list and displaying it.
src/app/app.component.html:
<form class="row g-3"> <div class="col-auto"> <label for="txtProductName" class="visually-hidden">Product Name</label> <input type="text" class="form-control" [(ngModel)]="gadgetForms.ProductName" id="txtProductName" name="txtProductName" placeholder="Product Name"> </div> <div class="col-auto"> <label for="txtBrand" class="visually-hidden">Brand</label> <input type="text" class="form-control" [(ngModel)]="gadgetForms.Brand" id="txtBrand" name="txtBrand" placeholder="Brand"> </div> <div class="col-auto"> <label for="txtCost" class="visually-hidden">Cost</label> <input type="text" class="form-control" [(ngModel)]="gadgetForms.Cost" id="txtCost" name="txtCost" placeholder="Cost"> </div> <div class="col-auto"> <label for="txtType" class="visually-hidden">Type</label> <input type="text" class="form-control" [(ngModel)]="gadgetForms.Type" id="txtType" name="txtType" placeholder="Type"> </div> <div class="col-auto"> <button type="submit" class="btn btn-primary mb-3" (click)="newGadget()">Add</button> </div> </form>Now test our application by creating a new record.So that's all about the small intro on Apollo Angular library to consume the GraphQL endpoint.
Video Session:
Support Me!
Buy Me A Coffee
PayPal Me
Wrapping Up:
Hopefully, I think this article delivered some useful information on integrating the Apollo Angular library to consume GraphQL endpoint in Angular application. I love to have your feedback, suggestions, and better techniques in the comment section below.
This was really helpful. I was actually looking for creating something similar though my output would be in the graph format. this provides me a great starting point. Bookmarked !
ReplyDelete