This article was published on Friday, November 30, 2018 by Kamil Kisiela @ The Guild Blog
By Doing GraphQL RightDid you know that Angular Console uses GraphQL under the hood? I want to tell about how it
used it and how I helped to improve it because that might be useful for people trying to implement
GraphQL in their applications, both on client and server.> Angular Console is a user interface for Angular CLI created by
Nrwl, widely used in Angular Community.
I will link to the PRs I've made to Angular Console throughout the article, so you could see
everything I recommend in practice.After reading
the announcement of
Angular Console I got very excited about the tool and immediately decided to explore the
codebase. I noticed Electron and that the project is based on Angular CLI and Nrwl's NX.That's super cool but what I found the most interesting was GraphQL.As a freelancer, I work on daily basis with The Guild. Most of our projects are built with
GraphQL. Throughout the 3 years of adopting it, our team tested practices and developed open
source tools that helped to improve our workflow.So when I saw the first implementation, I thought it would be nice to share some ideas and implement
some code that might help to improve the GraphQL part of Angular Console.## Apollo Angular as the GraphQL ClientI was hoping to find Apollo Angular as one of
dependencies. I might be a bit bias as the author of that library but our team used it in all of our
angular based projects with huge success.> KLM and AirFrance runs on Apollo AngularOkay, but just like in REST, you don't need sophisticated tools to communicate with the API. Simple
fetch
or Angular'sHttpClient
is far enough. Why then the GraphQL client?Having a client, like Apollo, allows you to easily execute GraphQL operations and by having a cache
layer, fetched data stays consistent across all components. Dhaivat Pandya explains it well in his
“Why you might want a GraphQL client”
post*.Apollo has a comprehensive documentation that covers a lot
of use cases, and I highly recommend to read it.## Using DI to Create ApolloAngular Console used an old way of initializing Apollo. In one of the recent versions of Apollo
Angular I introducedAPOLLO_OPTIONS
, an InjectionToken that provides a configuration object to
Apollo service. The old API caused an issue with a race condition where a service tried to use
Apollo before it got created.https://github.com/nrwl/nx-console/pull/158That was the first, very small PR. Next PR brought more changes and was focused only on the server.## Apollo Server 2.0I replacedexpress-graphql
with a more complete solution, Apollo Server. This move helped to
improve developer experience by having a **built-in support for GraphQL Subscription*, file
uploading and error handling. I'm pretty sure the team behind Angular Console have plans to take
advantage of it and implement subscriptions in the app, for example to replace currently used
polling technique.## Schema Definition LanguageSDL, in short, is a syntax that allows to define GraphQL Schema, so instead of using GraphQL's API,
you simply write everything as string.For example, usingGraphQLObjectType
might look like this:
new GraphQLObjectType({ name: 'Post', fields: { id: { type: GraphQLString }, text: { type: GraphQLString } } })
with Schema Definition Language:
type Post { id: String text: String }
In my opinion, it's more convenient and way more intuitive to work with.## Keeping Resolve Functions Separated from SDLIn our projects, we try to group resolvers by GraphQL type and have them nearby the corresponding
schema definition.Having both, type definition and resolve functions in theGraphQLObjectType
looks like that:
new GraphQLObjectType({ name: 'Post', fields: { id: { type: GraphQLString, resolve: parent => parent._id }, text: { type: GraphQLString, resolve: parent => parent.content } } })
I personally think it was a good choice because it forces developers to write logical part right
next to type definition. The problem is, the bigger types the more confusing it gets. Also keeping
resolvers as standalone functions makes them easier to test.With Schema Definition Language, it's looks way better.
const PostType = gql` type Post { id: String text: String } `
const Post = {
id: parent => parent._id,
text: parent => parent.content
}
Here are the relevant changes that I've mentioned above, that allowed me to introduce something
really interesting in the next PR.https://github.com/nrwl/nx-console/pull/175Apollo Server 2.0 Latest Apollo Angular refactoring — moved files under /api directory used SDL
instead of classes from…github.com')## Strongly Typed ResolversWe love [TypeScript](https://typescriptlang.org), and we saw an opportunity to take our GraphQL
servers to the next level. Instead of having `any` or defining interfaces for each resolver by hand,
we decided to take advantage of one of our tools, called
[GraphQL Code Generator](https://graphql-code-generator.com) (thanks Dotan Simha for creating it).In short, it's a tool to generate pretty much any piece of code, based on a GraphQL Schema. We use
it a lot, mostly for types (server and client) but also to create MongoDB models, introspection
files, Angular components and more.In Angular Console, I used the TypeScript plugins to generate types for a schema and also for
GraphQL Resolvers. It's one of the pieces that makes your code even more strongly typed, from end to
end.Here's how it might look like.
```ts
import { PostResolvers } from './generated-types'
const Post: PostResolvers.Resolvers = {
id: parent => parent._id,
text: parent => parent.content
}
export interface PostParent {
_id: string
content: string
}
If you want to take a look at the changes and read about GraphQL Code Generator:https://github.com/nrwl/nx-console/pull/185We recently released another new version of the GraphQL Code Generator that fixed a lot of issues,
introduced a feature called Mappers, made signatures of resolve functions more strict and handles
multiple results in parallel.https://github.com/nrwl/nx-console/pull/413The GraphQL Code Generator is one powerful beast that enables any kind of code generation based just
on GraphQL Schema (you can create your own custom generation templates).# Named OperationsGraphQL in most cases allows to use a shorthand syntax but putting a type and a name of an operation
is very useful, simply for debugging and logging. It's easier to track down a failed operation,
because it's no longer anonymous and by keeping all names unique you're able to take advantage of
any tool or service. One tool I described in the next chapter.## Strongly Typed Operations and Code GenerationFetching data with Apollo Angular, requires few steps:* Import Apollo
service
- Inject the service in a component
- Define GraphQL operation
- Wrap the operation with the
gql
tag - Call
Apollo.watchQuery
with the operation - Get an
Observable
with dataThat's a lot, and in order to have everything strongly typed you even have to define extra interfaces that are specific for each operation. ```typescript import { Apollo } from 'apollo-angular' import gql from 'graphql-tag'
interface Post {
id: string
text: string
}
interface PostQuery {
post: Post
}
@Component({
/.../
})
export class PostComponent {
@Input() postId: string
post: Observable
constructor(private apollo: Apollo) {}
ngOnInit() {
this.post = this.apollo
.watchQuery({
query: gql
,
query getPost($id: String!) {
post(id: $id) {
id
text
}
}
variables: {
id: this.postId
}
})
.valueChanges.pipe(map(result => result.data.post))
}
}
I wanted to share with Angular Console, something that we use and what helped to improve our
workflow.One interesting thing that we're able to achieve is the
[`apollo-angular` code-generator plugin](https://graphql-code-generator.com/docs/plugins/typescript-apollo-angular).Its main purpose is to generate strongly typed services for each GraphQL operation. Take a look at
the following scientific visualization:<Video src="/medium/f55951c146120a5fc45fa19066b8b6dd.webm" title="This is how magic happens." />Given the example I previously used, this is how it might look like with Apollo Angular plugin now.* Write a query in a `.graphql` file
* Run the codegen *(has watch mode)*
* Use a **fully typed generated Angular service** directly in your component
```graphql
query getPost($id: String!) {
post(id: $id) {
id
text
}
}
import { GetPostGQL, Post } from './generated/graphql';
@Component({...})
export class PostComponent {
@Input() postId: string;
post: Observable<Post>;
constructor(
private getPostGQL: GetPostGQL
) {}
ngOnInit() {
this.post = this.getPostGQL
.watch({ id: this.postId })
.valueChanges
.pipe(
map(result => result.data.post)
);
}
}
As you can see, we no longer use Apollo service directly (it's used under the hood) and every
operation has now strongly typed API.It wouldn't be possible without introducing this new API. I highly recommend to read an article
linked below, it explains what it is and how it could be used with the codegen./blog/apollo-angular-12I also prepared an explanation video that might help you to learn step by step, what code generation
is and how to use it in a project.Here is the relevant PR introducing this change into Angular Console:https://github.com/nrwl/nx-console/pull/219***https://github.com/nrwl/nx-console/pull/263## SummaryGraphQL is a very useful and fast growing technology. It helps with so many different use cases of
developing applications, large and small. But don't forget that the ecosystem of GraphQL is huge and
there are a lot of extra tools and best practices that might make it even more useful!I hope this post was helpful for you to learn about some handy things in GraphQL.
Top comments (0)