How I helped improve Angular Console

Kamil Kisiela
How I helped improve Angular Console - The Guild Blog

By doing GraphQL right

Did 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 client

I 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 Angular

Okay, but just like in REST, you don’t need sophisticated tools to communicate with the API. Simple fetch or Angular’s HttpClient 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 Apollo

Angular Console used an old way of initializing Apollo. In one of the recent versions of Apollo Angular I introduced APOLLO_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/158

That was the first, very small PR. Next PR brought more changes and was focused only on the server.

Apollo Server 2.0

I replaced express-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 Language

SDL, 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, using GraphQLObjectType 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 SDL

In 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 the GraphQLObjectType 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/175

Apollo Server 2.0 Latest Apollo Angular refactoring — moved files under /api directory used SDL instead of classes from…github.com')

Strongly typed resolvers

We love TypeScript 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 (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.

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/185

We 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/413

The 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 operations

GraphQL 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 generation

Fetching 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 data

That’s a lot, and in order to have everything strongly typed you even have to define extra interfaces that are specific for each operation.

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<Post>;

  constructor(private apollo: Apollo) {}

  ngOnInit() {
    this.post = this.apollo.watchQuery<PostQuery>({
      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.

Its main purpose is to generate strongly typed services for each GraphQL operation. Take a look at the following scientific visualization:

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
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-12

I 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

Summary

GraphQL 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.