This way, each module can declare only the part of the schema that it contributes, and the complete schema is a representation of all merged type definitions.

Module can also depend, import and extend and customize the contents on other modules (for example, User module, comes with Auth inside it)

The result of course, will be the same, because we are merging the schema into a single one, but the codebase will be much more organized and each module will have its own logic.

Reusability of backend modules

So now that we understood the power of feature-based implementation, it’s easier to grasp the idea behind code reusability.

If we could implement the schema and the core of Auth and User module as “plug-and-play” — we will be able later to import it in other projects, with very minor changes (using configuration, dependency injection, or module composition).

How could we reuse complete modules that hold part of a schema?

For example, let’s take a User type.

Most of User type schemas will contain id , email and username fields. The Mutation type will have login and the Query will have user field to query for a specific user.

We can re-use this type declaration.

The actual implementation might differ between apps, according to the authentication provider, database and so on, but we can still implement the business logic in a simple resolver, and use dependency injector and ask the app that’s using the module to provide the actual authentication function (of course, with a complete TypeScript interface so we’ll know that we need to provide it ;) ).

Let’s take it one step further. If we would like to add a profile picture to a user, we can add a new module named UserProfile and re-declare the User and Mutation types again:

This way, GraphQL Modules will merge the fields from this User type into the complete User type, and this module will only extend the User type and Mutation type with the required actions.

So let’s say that we have the schema — how can we make this module generic and re-use it?

This is how you declare this module:

We declare a config object, and the app will provide it for us, so we can later replace it with a different logic for uploading.

Scaling the codebase

Now that we broke our app into individual modules, once our codebase grows, we can scale each module individually.

What do I mean by scaling a codebase?

Let’s say we start to have code parts we want to share between different modules.

The current way of doing it in the existing GraphQL world is through a GraphQL context.

This approach has proven itself to work, but at some point it becomes a big hassle to maintain, because GraphQL context is an object, which any part of the app can modify, edit and extend, and it can become really big pretty quickly.

GraphQL modules let each module extend and inject fields to the `context` object, but this is something that you should use with caution, because I recommend the `context` to contain the actual `context` — which contains data such as global configuration, environment, the current user and so on.

GraphQL modules only adds one field under the context , called injector which is the bridge that lets you access your GraphQLApp and the application Injector, and it lets you fetch your module’s config and providers.

Modules can be a simple directory in a project or in a monorepo, or it could be a published NPM module — you have the power to choose how to manage your codebase according to your needs and preferences.

Dependency Injection

GraphQL Modules’ dependency injection is inspired by .NET and Java’s dependency injection which has proven itself to work pretty well over the years. With that being said, there were some issues with .NET and Java’s APIs, which we’ve tried to list and go through. We ran into some pretty interesting conclusions.

We’ve learn that it’s not something that should be forced. Dependency injection makes sense in some specific use cases and you should need to use it only when it’s necessary and when it helps you move faster. So this concept should come more and more in handy as we scale up, we can simplify things, maintain our code with ease and manage our teams’ contributions!

Having GraphQL Modules deployed across all of our Enterprise customers while also being used on our smaller applications, lead us to believe that we’ve found the optimal point of where you should use the concept of dependency injection, and when not.

We’ve also came with the optimal API for dependency injection. It’s extremely easy to understand, and use.

After a long research of the existing dependency injection solutions for JavaScript, we’ve decided to implement a simple Injector, that supports the needs of GraphQL-Modules ecosystem, and support circular dependencies and more.

We’ve simplified the Dependency Injection API and exposed to you only the important parts, that we believe that are necessary for a GraphQL server development.

Authentication

Check out the related blog post we wrote about it: https://medium.com/the-guild/authentication-and-authorization-in-graphql-and-how-graphql-modules-can-help-fadc1ee5b0c2

Testing and mocking

On our Enterprise applications, when we started using dependency injection, we no longer had to manage instances and bridge them together.

We gained an abstraction that allowed us to test things easier and mock all http requests.

Yes, mocking. DI really shines here.

Thanks to mocking we can simulate many scenarios and check the backend against them.

And when your codebase grows, you need to start thinking about managing dependencies between modules and how to avoid things like circular dependencies — unless you use DI which solves that problem for you.

With the power of dependency injection, you can easily create a loose connection between modules, and base this connection on a token and on a TypeScript interface.

It also means that testing is much easier — you can take your class/function and test it as an independent unit, and mock its dependencies easily.

Summary

We see GraphQL Modules as the framework that finally being built from the ground up on the new and exciting capabilities of GraphQL and Apollo, while combining it in the right way with good old software best practices for scale like modularizations, strong typings and dependency injection.

Now go and try it out — https://graphql-modules.com/