Query, Mutation, Subscription Services
If you’re familiar with the library, you already know the Apollo service. It is a regular Angular service, pretty much the only one you need to use.
The API is straightforward, query
and watchQuery
methods for Queries, mutate
and subscribe
accordingly for Mutations and Subscriptions. There is more than that but if you don’t do anything
advanced that’s all you really need.
We decided to introduce a new approach of working with GraphQL in Angular.
There are now 3 new APIs: Query
, Mutation
and Subscription
. Each of them allows to define the
shape of a result & variables. The only thing you need to do is to set the document property. That’s
it, you use it as a regular Angular service.
In this approach GraphQL Documents are first-class citizens, you think about the query, for example, as a main subject.
The best part about the new API is that you don’t have to create those services, there’s a tool that does it for you.
To read more about it, go to “Code Generation” section.
Query
To get started with the new API, let’s see how you define queries with it.
You create a service and extend it with a Query
class from apollo-angular
. Only thing you need
to set is a document
property.
import { gql, Query } from 'apollo-angular';
import { Injectable } from '@angular/core';
export interface Post {
id: string;
title: string;
votes: number;
author: {
id: string;
firstName: string;
lastName: string;
};
}
export interface Response {
posts: Post[];
}
@Injectable({
providedIn: 'root',
})
export class AllPostsGQL extends Query<Response> {
document = gql`
query allPosts {
posts {
id
title
votes
author {
id
firstName
lastName
}
}
}
`;
}
We have now a ready to use GraphQL Query that takes advantage of Apollo
service under the hood.
Basic Example
Let’s see how to actually use it in a component:
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Component, OnInit } from '@angular/core';
// import a service
import { AllPostsGQL, Post } from './graphql';
@Component({
// ...
})
export class ListComponent implements OnInit {
posts: Observable<Post[]>;
// inject it
constructor(private readonly allPostsGQL: AllPostsGQL) {}
ngOnInit() {
// use it!
this.posts = this.allPostsGQL.watch().valueChanges.pipe(map(result => result.data.posts));
}
}
Example with Variables
@Component({
// ...
})
export class ListComponent implements OnInit {
// ...
ngOnInit() {
// variables as first argument
// options as second
this.posts = this.allPostsGQL
.watch(
{
first: 10,
},
{
fetchPolicy: 'network-only',
},
)
.valueChanges.pipe(map(result => result.data.posts));
}
}
API of Query
Query
class has two methods:
watch(variables?, options?)
- it’s the same asApollo.watchQuery
except it accepts variables as a first argument and regular options as the second onefetch(variables?, options?)
- same asApollo.query
, it fetches data once.
Mutation
You create a service and extend it with a Mutation
class from apollo-angular
. Only thing you
need to set is a document
property.
import { gql, Mutation } from 'apollo-angular';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class UpvotePostGQL extends Mutation {
document = gql`
mutation upvotePost($postId: Int!) {
upvotePost(postId: $postId) {
id
votes
}
}
`;
}
We have now a ready to use GraphQL Mutation.
Basic Example
Let’s see how to actually use it in a component:
import { Component, Input } from '@angular/core';
import { UpvotePostGQL } from './graphql';
@Component({
selector: 'app-upvoter',
template: `<button (click)="upvote()">Upvote</button>`,
})
export class UpvoterComponent {
@Input()
postId: number;
constructor(private readonly upvotePostGQL: UpvotePostGQL) {}
upvote() {
this.upvotePostGQL
.mutate({
postId: this.postId,
})
.subscribe();
}
}
API of Mutation
Mutation
class has only one method:
mutate(variables?, options?)
- it’s the same asApollo.mutate
except it accepts variables as a first argument and regular options as the second one.
Subscription
You create a service and extend it with a Subscription
class from apollo-angular
. Only thing you
need to set is a document
property.
import { gql, Subscription } from 'apollo-angular';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class NewPostGQL extends Subscription {
document = gql`
subscription newPost {
newPost {
id
title
}
}
`;
}
We have now a ready to use GraphQL Subscription.
Basic Example
Let’s see how to actually use it in a component:
import { Component } from '@angular/core';
import { NewPostGQL } from './graphql';
@Component({
// ...
})
export class ActivityComponent {
constructor(newPostGQL: NewPostGQL) {
this.lastPost = newPostGQL.subscribe();
}
}
API of Subscription
Subscription
class has only one method:
subscribe(variables?, options?, extraOptions?)
- it’s the same asApollo.subscribe
except its first argument expect variables.
Code Generation
There’s a tool to generate a ready to use in your component, strongly typed Angular services, for every defined query, mutation or subscription.
In short, you define a query in .graphql
file so your IDE gives you autocompletion and validation.
query allPosts {
posts {
id
title
votes
author {
id
firstName
lastName
}
}
}
Code generation tool outputs to a file, a fully featured service called AllPostsGQL
with every
interface you will need.
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Component, OnInit } from '@angular/core';
// import a service and a type from the generated output
import { AllPostsGQL, Post } from './generated';
@Component({
// ...
})
export class ListComponent implements OnInit {
posts: Observable<Post[]>;
// inject it
constructor(private readonly allPostsGQL: AllPostsGQL) {}
ngOnInit() {
// use it!
this.posts = this.allPostsGQL.watch().valueChanges.pipe(map(result => result.data.posts));
}
}
To learn more about the tool, please read the “Apollo-Angular 1.2 — using GraphQL in your apps just got a whole lot easier!” article or go straight to documentation.