How to enable subscription in Apollo Federation with nestJS graphql
Tags: nestjs, graphql, apollo
Published: 2021-09-18 14:01:22

<div class="wp-block-cover has-background-dim"><img class="wp-block-cover__image-background wp-image-383" alt="" src="https://vinodsr.com/myblog/wp-content/uploads/2021/07/apollo-federation1.jpg" data-object-fit="cover"/><div class="wp-block-cover__inner-container"><!-- wp:paragraph {"align":"center","placeholder":"Write title…","fontSize":"large"} -->
<p class="has-text-align-center has-large-font-size"></p>
<!-- /wp:paragraph --></div></div>
<!-- /wp:cover -->

<!-- wp:paragraph -->
<p></p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>NestJS with GraphQL</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Setting up a graphQL server in nestJS saves 5x-10x of the effort with vanilla nodejs. NestJS uses the standard apollo library for setting up the graphQL. It supports both normal and federation mode. In federation mode, we can setup graphql servers in every microservices, which can be aggregated using a gateway; Just like API-Gateway with REST services. It is a very good technique if you are running microservices and want to separate the responsibility for each service.</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>NestJS is one of the powerful nodejs framework available as of today. One of the cool features of nestJS is that it allows easy integration with databases, message queues, authentication etc. Further more it allows developers to create application  using nodeJS with in a much stricter, robust and flexible framework like Spring Boot / Angular.</p><p>If you are new to nestJS head over to <a href="https://docs.nestjs.com">https://docs.nestjs.com</a> for getting started. This article expects that you have a prior knowledge of setting up and running nestJS.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:heading -->
<h2>Contents</h2>
<!-- /wp:heading -->

<!-- wp:list -->
<ul><li><a href="#theproblem" title="#theproblem">the problem</a></li><li><a href="#theproblem" title="#theproblem">solution</a></li><li><a href="#theproblem" title="#theproblem">conclusion</a></li><li><a href="#bonustip">bonus tip</a></li></ul>
<!-- /wp:list -->

<!-- wp:heading -->
<h2 id="theproblem">the problem</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p> All this comes with some inherent caveats from the apollo library. While setting up the federation you cannot use graphql subscription. </p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":355,"sizeSlug":"large","linkDestination":"none"} -->
<figure class="wp-block-image size-large"><img src="https://vinodsr.com/myblog/wp-content/uploads/2021/07/Federation-error-subs-1024x69.png" alt="" class="wp-image-355"/><figcaption>You will probably see this error</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Apollo had come up with an <a href="https://www.apollographql.com/blog/backend/federation/using-subscriptions-with-your-federated-data-graph/" target="_blank" rel="noreferrer noopener">approach </a>to over come this problem. But it over complicates the situation. Lets see how to tackle this problem using the features in nestJS. In the example i am using the <a href="https://docs.nestjs.com/graphql/resolvers#schema-first" target="_blank" rel="noreferrer noopener">schema first approach</a>. The same approach can be implemented in the <a href="https://docs.nestjs.com/graphql/resolvers#code-first" target="_blank" rel="noreferrer noopener">code based approach</a>. </p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 id="solution">solution</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>The solution to this problem is to hide the subscription based schema for the federation server and host the subscription based graphql as a separate normal graphql server. Seems very simple huh ? Not that easy :) . We will cover the method with some simple steps. </p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>step 1 : Classify Schema</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>The primary step is to separate your graphql schema in to different files as per the below conventions. </p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><li><strong>*.graphq</strong>l : for graphql syntax supported in both federation and normal mode</li><li><strong>*.graphql.federation</strong> : for syntax supported only in federation mode (eg : extends)</li><li><strong>*.graphql.normal</strong> : for syntax supported only in normal mode (eg : subscription)</li></ol>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Save the subscription model in any "<em><strong>graphql.normal</strong></em>" file</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center","id":356,"sizeSlug":"large","linkDestination":"none"} -->
<div class="wp-block-image"><figure class="aligncenter size-large"><img src="https://vinodsr.com/myblog/wp-content/uploads/2021/07/vscode-formatted.png" alt="" class="wp-image-356"/></figure></div>
<!-- /wp:image -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>You can give any name you would like to. This tutorial follows this naming convention.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:heading {"level":4} -->
<h4>step 2 : configure server</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Setup the app.module.ts with two graphql modules, one for the normal server and another for the federation server.  We need to configure the module in such a way that the only federation module loads the <code><strong>.graphql.federation</strong></code> file and only normal module loads the <code><strong>graphql.normal</strong></code> file. The <strong><code>.graphql</code></strong> file has to be loaded by both modules.</p>
<!-- /wp:paragraph -->

```typescript
  imports: [
    GraphQLModule.forRoot({
      debug: false,
      playground: true,
      path: '/graphql',
      typePaths: ['./**/*.{graphql,graphql.normal}'],
      installSubscriptionHandlers: true,
    }),
    GraphQLFederationModule.forRoot({
      debug: false,
      playground: false,
      path: '/graphql-federated',
      typePaths: ['./**/*.{graphql,graphql.federation}'],
    }),
  ],
```

<!-- wp:paragraph -->
<p>Notice that type paths for the two modules are different as per our convention. The normal graphql with subscription is now available at <code>/grapqhl</code> and the  server for federation gateway is available at <code>/graphql-federated</code></p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p><em><span style="color:#6d6e70" class="has-inline-color">We are not spinning two servers here. Its the same express server with two middleware configured for different paths. So there will not be any performance issues</span></em></p></blockquote>
<!-- /wp:quote -->

<!-- wp:heading {"level":4} -->
<h4>step 3 : the illusion</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>This is the most important step. There are some directives in graphql that only works in the federated mode and vice versa. You will finally end up in writing the custom version of the grapqhl model in the federated and the normal files. This will add the headache of duplicate graphql models in the application.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This problem can be tackled in a easy way , using dummy directives !</p>
<!-- /wp:paragraph -->

Define a declarative for “key” in __*key.directive.ts*__


```typescript
import { SchemaDirectiveVisitor } from 'apollo-server-express';
import { GraphQLField } from 'graphql';

/**
 * This is a dummy implementation of the key directive for the normal mode
 */
export class FakeKeyDirective extends SchemaDirectiveVisitor {
  /**
   * Fake Key definition
   * @param _field Field of graphql
   */
  visitFieldDefinition(_field: GraphQLField&lt;any, any&gt;) {
    _field.args;
  }
}
```


Include it in the module (__*app.module.ts*__)


```typescript
@Module({
  imports: [
    GraphQLModule.forRoot({
      debug: false,
      playground: true,
      path: '/graphql',
      typePaths: ['./**/*.{graphql,graphql.normal}'],
      installSubscriptionHandlers: true,

      directiveResolvers: {
        key: FakeKeyDirective,
      },
    }),
    GraphQLFederationModule.forRoot({
      debug: false,
      playground: false,
      path: '/graphql-federated',
      typePaths: ['./**/*.{graphql,graphql.federation}'],
    }),
  ],
  controllers: [AppController],
  providers: [AppService, UsersResolver, UserService],
})
export class AppModule {}
```

<!-- wp:list -->
<ul><li>Define a fake implementation. This only has to work in the normal mode. So the file name has to end with “graphql.normal” say "key.graphql.normal" </li></ul>
<!-- /wp:list -->


```typescript
directive @key(fields: String) on OBJECT
```

<!-- wp:paragraph -->
<p>Now you can define the model using the federation supported @key directive and the model works both in federation and normal graphql server. Let's edit "departments.graphql"</p>
<!-- /wp:paragraph -->


```typescript
type Department @key(fields: "id") {
  id: ID!
  name: String
}
```

<!-- wp:heading -->
<h2>thats all folks</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p> Now you can start the federation gateway which listens to the the<code> /graphql-federated</code> and the federation works. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>For subscription you can use any Websocket enabled gateways like nginx, istio etc and connect directly to the microservices</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 id="conclusion">conclusion</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Yes it is possible to enable federation and subscription for graphql in nestJS using a simple trick. More efficient than the <a href="https://www.apollographql.com/blog/backend/federation/using-subscriptions-with-your-federated-data-graph/" target="_blank" rel="noreferrer noopener">Apollo </a>method. You can download the entire code for your reference from my <a href="https://github.com/vinodsr/nestjs-graphql-federation-with-subscription" target="_blank" rel="noreferrer noopener">github repo (https://github.com/vinodsr/nestjs-graphql-federation-with-subscription</a>)<a href="https://github.com/vinodsr/nestjs-graphql-federation-with-subscription" target="_blank" rel="noreferrer noopener">.</a></p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 id="bonustip">bonus tip</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Since you are using a separate file extension other than .graphql, your IDE won’t give the native graphql formatting for the graphql.normal and graphql.federation files. There is a fix for this. Just enabled file associations for those extensions. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This is how it looks like in VS Code. Adding the file extensions will give you syntax highlighting and code formatting for the normal and federation graphql. </p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":361,"sizeSlug":"large","linkDestination":"none"} -->
<figure class="wp-block-image size-large"><img src="https://vinodsr.com/myblog/wp-content/uploads/2021/07/image-2.png" alt="" class="wp-image-361"/></figure>
<!-- /wp:image -->


{% github vinodsr/nestjs-graphql-federation-with-subscription no-readme%}