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
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.
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?
- Sharing Services is
now easier than ever, all you need to do is to set
global: true
flag in@Injectable
decorator. - There's a space for abstraction. Each Module has its own Injector that has Injector of an application as a parent.
- Only two kinds of scope:
Singleton
andOperation
. We think it's simpler this way and the naming is much more intuitive. - Richer error messages, new DI gives you more details about what went wrong.
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
}
}
}
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)
}
}
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'
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.
Top comments (0)