DEV Community

Cover image for The New GraphQL Modules
TheGuildBot for The Guild

Posted on • Edited on • Originally published at the-guild.dev

The New GraphQL Modules

This article was published on Monday, December 21, 2020 by Kamil Kisiela @ The Guild Blog

History Lesson

GraphQL Modules showed up on NPM almost 3 years ago, but now we
decided to rewrite it from scratch. Throughout those years the library improved by a lot of thanks
to the community and the companies we as The Guild worked with.

We tried to implement new ideas and revamp the library without touching the core.

That was until now, we decided to finally change the fundamentals of GraphQL Modules according to
the collected feedback from our users.

New Major Version

We were planning a new major release from quite some time now and after few months of work, it's
finally available!

  • Much richer error messages
  • More advanced and much more flexible Dependency Injection
  • Flat structure - one application, many modules
  • Testing utilities
  • Functions instead of classes
  • Better performance
  • Simpler codebase
  • In general, better Developer Experience
  • GraphQL Codegen support with GraphQL Modules preset

We know those are just words, but we've been using it for a while, and we love it!

Single Package

We decided to merge two existing packages @graphql-modules/core and @graphql-modules/di into a
single package graphql-modules. There's no regression in terms of bundle size, because core was
importing di anyway.

yarn remove @graphql-modules/core @graphql-modules/di
yarn add graphql-modules
Enter fullscreen mode Exit fullscreen mode

Making GraphQL Modules a single package should improve the developer experience.

Flat Structure

In 1.0, we changed the structure of GraphQL Modules to be flat. We also added Application level
that represents the root of your GraphQL API.

Flat structure

You no longer need to define imports and strict dependencies between modules, since they are all
flatten and merged together by the Application.

Improved Dependency Injection

The previous version was lacking proper abstraction, it was extremely hard to test and in general
very strict.

Thanks to the flat structure of GraphQL Modules we were able to rethink the implementation of
Dependency Injection. What are the benefits?

Dependency Injection hierarchy

Stronger Type-Safety

GraphQL Modules expose a global namespace called GraphQLModules, so there's no need to pass the
same signature over and over again as part of generic types of different APIs.

Context is global and shared across modules and application which means you can define it once, and
it applies automatically everywhere.

Use and extend GraphQLModules.GlobalContext like this:

declare global {
  namespace GraphQLModules {
    interface GlobalContext {
      request: any
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

We created a special GraphQL-Code-Generator preset for GraphQL Modules.

It generates a complete, unified, type signature for your schema, and sub-files per each module,
containing only the GraphQL types declared/extended in your specific module.

To get started,
follow the instructions in graphql-code-generator.com website.

Shared Context

In v0, you could create a context per each module. In v1, context is external for GraphQL-Modules,
and it's not directly in use. You can do whatever you want with that, and just access it in
GraphQL-Modules if you need, but we no longer require you to do specific things with your context.

Dynamic Singletons - @ExecutionContext

Execution Context means the context of execution of GraphQL Operation. In short, it's the context
value created by your GraphQL server.

Singletons can't directly access Operation scoped services, meaning they probably can't also
directly access the context object created per each operation. Directly.

Thanks to @ExecutionContext decorator, every Singleton provider gets access to the GraphQL Context
and the Operation scoped Injector.

import { ExecutionContext, Injectable } from 'graphql-modules'
import { Config } from './config'

@Injectable()
export class Data {
  constructor(private config: Config) {}

  @ExecutionContext()
  private context: ExecutionContext

  someMethod() {
    console.log('Environment', this.config.env)

    const value = this.context.injector.get(SOME_TOKEN)
  }
}
Enter fullscreen mode Exit fullscreen mode

You gain a lot in terms of performance, because the Data class is instantiated only once and used
in many operations.

Testing Kit

GraphQL Modules provides
a set of utilities for testing your modules
and also for more granular testing of module's smaller units, like providers and middlewares.

To access the testing utilities, import testkit object from graphql-modules package:

import { testkit } from 'graphql-modules'
Enter fullscreen mode Exit fullscreen mode

The testkit object and its API will grow over time, we expect to implement more and more useful
features in upcoming releases.

Migration

The v1.0 is a total rewrite, there are of course breaking changes.

We prepared an entire chapter in documentation that covers pretty much all breaking changes and new
features. Please read "Migration from v0.X"
chapter and give us a feedback.

The documentation of 0.x version of GraphQL Modules
is available under legacy name.
The same applies to the codebase, there's the
legacy branch on the repository.


Oh, and Happy New Year!

Happy New Year

Top comments (0)