### Express GraphQL Setup with Subscriptions Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/advanced/subscriptions.mdx Set up Express GraphQL to support subscriptions using `express-graphql` and `subscriptions-transport-ws`. This example shows how to integrate custom execution and subscription functions from GraphQL Modules. ```typescript import 'reflect-metadata' import express from 'express' import graphqlHTTP from 'express-graphql' import { createServer } from 'node:http' import { SubscriptionServer } from 'subscriptions-transport-ws' import { application } from './application' const execute = application.createExecution() const subscribe = application.createSubscription() const { schema } = application const server = express() server.use( '/', graphqlHTTP({ schema, customExecuteFn: execute, ``` -------------------------------- ### Install GraphQL Modules Source: https://github.com/graphql-hive/graphql-modules/blob/master/packages/graphql-modules/README.md Install the graphql-modules package using npm or yarn. ```sh npm install graphql-modules # Or, with Yarn yarn add graphql-modules ``` -------------------------------- ### Install GraphQL Modules Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/get-started.mdx Install the necessary packages for GraphQL Modules using npm or yarn. ```sh npm i graphql-modules graphql ``` -------------------------------- ### Set up GraphQL Subscriptions Server Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/advanced/subscriptions.mdx Integrates GraphQL subscriptions with an existing Express server. Ensure `subscriptions-transport-ws` is installed. ```javascript import { createServer } from 'http' import express from 'express' import { execute, subscribe } from 'graphql' import { SubscriptionServer } from 'subscriptions-transport-ws' // Assume schema, app, and execute/subscribe are defined elsewhere const app = express() const webServer = createServer(app) webServer.listen(4000, () => { console.log('🚀 Server ready at http://localhost:4000') new SubscriptionServer( { execute, subscribe, schema }, { server: webServer, path: '/' } ) }) ``` -------------------------------- ### GraphQL Yoga Server Setup Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/advanced/subscriptions.mdx Integrate GraphQL Modules with GraphQL Yoga for a subscription-enabled server. This setup uses `@envelop/graphql-modules` to enable the application within the Yoga server. ```typescript import 'reflect-metadata' import { createServer } from '@graphql-yoga/node' import { useGraphQLModules } from '@envelop/graphql-modules' import { application } from './application' const server = createServer({ plugins: [useGraphQLModules(application)] }) server.start().then(() => { console.log(`🚀 Server ready`) }) ``` -------------------------------- ### Install GraphQL Modules Source: https://github.com/graphql-hive/graphql-modules/blob/master/README.md Use npm or yarn to add the graphql-modules package to your project. ```sh npm install graphql-modules # Or, with Yarn $ yarn add graphql-modules ``` -------------------------------- ### Creating a GraphQL Application Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/api.mdx Create a GraphQL application by providing a configuration object that includes a list of modules. This function orchestrates the setup of your GraphQL schema and resolvers. ```typescript import { createApplication } from 'graphql-modules' import { usersModule } from './users' import { postsModule } from './posts' import { commentsModule } from './comments' const app = createApplication({ modules: [usersModule, postsModule, commentsModule] }) ``` -------------------------------- ### Create Subscription Handler Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/advanced/subscriptions.mdx Use `createApplication` to set up your GraphQL modules and then call `createSubscription` to get a handler for subscription events. This is essential for managing the subscription lifecycle and preventing memory leaks. ```typescript import { createApplication } from 'graphql-modules' const application = createApplication({ modules: [ // ... ] }) const subscribe = application.createSubscription() ``` -------------------------------- ### Dynamically Load Resolver Files Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/resolvers.mdx Use `@graphql-tools/load-files` to dynamically load type definitions and resolvers from specified directories. Ensure the package is installed. ```shell npm i @graphql-tools/load-files ``` ```typescript import { createModule } from 'graphql-modules' export const myModule = createModule({ id: 'my-module', dirname: __dirname, typeDefs: loadFilesSync(join(__dirname, './typeDefs/*.graphql')), resolvers: loadFilesSync(join(__dirname, './resolvers/*.ts')) }) ``` -------------------------------- ### Integrate with GraphQL Yoga Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/get-started.mdx Use the `useGraphQLModules` plugin from Envelop to integrate with GraphQL Yoga. Ensure Envelop is installed and configured. ```typescript import { createServer } from 'node:http' import { createYoga } from 'graphql-yoga' import { useGraphQLModules } from '@envelop/graphql-modules' import { application } from './application' const yoga = createYoga({ plugins: [useGraphQLModules(application)] }) const server = createServer(yoga) server.listen(4000, () => { console.log(`🚀 Server ready`) }) ``` -------------------------------- ### Custom Execution and Subscription Functions Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/get-started.mdx Retrieve custom `execute` and `subscribe` functions from your `Application` instance to integrate with custom server setups. ```typescript import { createApplication } from 'graphql-modules' const application = createApplication({ /* ... */ }) const schema = application.schema const execute = application.createExecution() const subscribe = application.createSubscription() ``` -------------------------------- ### Apollo Server Setup with Subscriptions Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/advanced/subscriptions.mdx Configure Apollo Server to handle GraphQL Subscriptions with GraphQL Modules. This involves creating an HTTP server, setting up `ApolloServer`, and integrating `SubscriptionServer` for WebSocket communication. ```typescript import 'reflect-metadata' import express from 'express' import { createServer } from 'node:http' import { SubscriptionServer } from 'subscriptions-transport-ws' import { ApolloServer } from 'apollo-server-express' import { application } from './application' const schema = application.createSchemaForApollo() const { schema, createExecution, createSubscription, createApolloExecutor } = application const execute = createExecution() const subscribe = createSubscription() ;(async function () { const app = express() const httpServer = createServer(app) let subscriptionServer const server = new ApolloServer({ schema, executor: createApolloExecutor(), plugins: [ { serverWillStart() { return { drainServer() { subscriptionServer.close() } } } } ] }) subscriptionServer = SubscriptionServer.create( { schema, execute, subscribe }, { server: httpServer, path: server.graphqlPath } ) await server.start() server.applyMiddleware({ app }) const PORT = 4000 httpServer.listen(PORT, () => console.log(`Server is now running on http://localhost:${PORT}/graphql`) ) })() ``` -------------------------------- ### V0 Context Management in GraphQL Module Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/recipes/migration.mdx Example of context management in V0, where the `context` function within `GraphQLModule` is used to define the execution context for each session. ```typescript const MyModule = new GraphQLModule({ context(session: MyModuleSession) { session.res.on('finish', () => { // Some cleanup }) return { authToken: session.req.headers.authorization } } }) ``` -------------------------------- ### Define Basic Resolvers in GraphQL-Modules Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/resolvers.mdx Implement resolvers for your schema types within the `createModule` configuration. This example shows resolvers for a `Query` type and a `User` type. ```typescript import { createModule, gql } from 'graphql-modules' export const myModule = createModule({ id: 'my-module', dirname: __dirname, typeDefs: gql` type Query { user(id: ID!): User } type User { id: ID! username: String! } `, resolvers: { Query: { user(root, { id }) { return { _id: id, username: 'jhon' } } }, User: { id(user) { return user._id }, username(user) { return user.username } } } }) ``` -------------------------------- ### Test GraphQL Module Middleware Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/testing.mdx Use `testkit.testModule` to create an instance of your module for testing. This example tests an authentication middleware by providing a mock context and asserting that the operation fails when the user is not logged in. ```typescript import 'reflect-metadata' import { testkit, gql } from 'graphql-modules' import { myModule } from './my-module' test('ing', () => { const app = testkit.testModule(myModule) const result = await testkit.execute(app, { document: gql` { me { name } } `, contextValue: { isLoggedIn: false } }) expect(result.errors).toHaveLength(1) expect(result.data.me).toBeNull() }) ``` -------------------------------- ### V1 Module Configuration with Custom Tokens Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/recipes/migration.mdx In V1, `ModuleConfig` is replaced by custom injection tokens for configuration. This example shows how to define and use a custom token for module configuration. ```typescript import { createModule, InjectionToken } from '@graphql-modules/core' export interface MyModuleConfig { secretKey: string remoteEndpoint: string someDbInstance: SomeDBInstance } export const MyConfig = new InjectionToken() export const createMyModule = (config: MyModuleConfig) => createModule({ // ... providers: [ { provide: MyConfig, useValue: config } ] }) const application = createApplication({ modules: [ createMyModule({ secretKey: '123', remoteEndpoint: 'http://...', someDbInstance: db }) ] }) ``` ```typescript @Injectable() export class MyProvider { constructor(@Inject(MyConfig) private config: MyModuleConfig) { // ... } } ``` -------------------------------- ### Operation-Scoped Service with Lifecycle Hooks Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/advanced/lifecycles.mdx Defines an operation-scoped service that utilizes constructor for setup and `onDestroy` for cleanup when the operation context is destroyed. ```typescript import { Injectable, Scope, OnDestroy } from 'graphql-modules' @Injectable({ scope: Scope.Operation }) export class Data implements OnDestroy { constructor() { // incoming operation, here you can do your setup and preparation } onDestroy() { // Operation is resolved // Execution context is about to be disposed } } ``` -------------------------------- ### Import Reflect Metadata for DI Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/di/introduction.mdx Ensure Reflect API is available for Dependency Injection by importing 'reflect-metadata' at the very beginning of your application setup. This is crucial for GraphQL Modules' DI functionality. ```typescript import 'reflect-metadata' /* code */ ``` -------------------------------- ### Extend Resolvers with Grafast Plan Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/resolvers.mdx Utilize the `extensions` property within a resolver to integrate with libraries like Grafast for advanced features such as specifying a plan resolver. This example sets a constant value for `meaningOfLife`. ```typescript import { createModule, gql } from 'graphql-modules' import { constant } from "grafast"; export const myModule = createModule({ id: 'my-module', dirname: __dirname, typeDefs: [ gql` type Query { meaningOfLife: Int! } ` ], resolvers: { Query: { meaningOfLife: { extensions: { grafast: { plan() { return constant(42); }, }, }, }, } } }) ``` -------------------------------- ### Create a GraphQL Application Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/get-started.mdx Set up a GraphQL application by providing your created modules to `createApplication`. ```typescript import { createApplication } from 'graphql-modules' import { myModule } from './my-module' // This is your application, it contains your GraphQL schema and the implementation of it. const application = createApplication({ modules: [myModule] }) // This is your actual GraphQL schema const mySchema = application.schema ``` -------------------------------- ### createApplication Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/api.mdx Creates an Application instance from a list of GraphQL Modules and configuration. Accepts an `ApplicationConfig` object. ```APIDOC ## createApplication Creates Application out of Modules. Accepts `ApplicationConfig`. ```ts import { createApplication } from 'graphql-modules' import { usersModule } from './users' import { postsModule } from './posts' import { commentsModule } from './comments' const app = createApplication({ modules: [usersModule, postsModule, commentsModule] }) ``` ``` -------------------------------- ### Create a GraphQL Module and Application Source: https://github.com/graphql-hive/graphql-modules/blob/master/README.md Define a GraphQL module with its schema and resolvers, then create an application using that module. Requires importing necessary functions from 'graphql-modules'. ```javascript import { createModule, createApplication, gql } from 'graphql-modules' const module = createModule({ id: 'my-module', typeDefs: gql` type Post { id: ID title: String author: User } type Query { posts: [Post] } `, resolvers: blogResolvers }) const application = createApplication({ modules: [module] }) ``` -------------------------------- ### Module/Application Structure: V1 vs V0 Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/recipes/migration.mdx Compares the module and application structure, highlighting v1's flat module approach with `createApplication` versus v0's hierarchical `imports`. ```typescript const moduleOne = createModule({ ... }) const moduleTwo = createModule({ ... }) const application = createApplication({ modules: [moduleOne, moduleTwo] }) ``` ```typescript const moduleOne = new GraphQLModule({ ... }) const moduleTwo = new GraphQLModule({ imports: [moduleOne], ... }) const rootModule = new GraphQLModule({ imports: [moduleTwo] }) ``` -------------------------------- ### Create Your First GraphQL Module Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/get-started.mdx Define a basic GraphQL module using `createModule`, including its ID, type definitions, and resolvers. ```typescript import { createModule, gql } from 'graphql-modules' export const myModule = createModule({ id: 'my-module', dirname: __dirname, typeDefs: [ gql` type Query { hello: String! } ` ], resolvers: { Query: { hello: () => 'world' } } }) ``` -------------------------------- ### Module Instantiation: createModule vs new GraphQLModule Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/recipes/migration.mdx Shows the shift from instantiating `GraphQLModule` as a class in v0 to using the `createModule` utility function in v1. ```typescript const myModule = createModule({ ... }) ``` ```typescript const myModule = new GraphQLModule({ ... }) ``` -------------------------------- ### Test Module Configuration with Providers and Middlewares Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/testing.mdx Use `testkit.testModule` to create an application instance for testing. Configure providers and middlewares at the application level. ```typescript import 'reflect-metadata' import { testkit } from 'graphql-modules' import { myModule } from './my-module' import { myMiddleware } from './my-middleware' import { MyProvider } from './my-provider' test('ing', () => { const app = testkit.testModule(myModule, { providers: [ { provide: MyProvider, useValue: {} } ], middlewares: { Query: { '*': [myMiddleware] } } }) }) ``` -------------------------------- ### Create Application with PubSub Singleton Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/advanced/subscriptions.mdx Configure the GraphQL application to provide a singleton instance of `PubSub` from `graphql-subscriptions`. This ensures the same `PubSub` instance is available across all modules. ```typescript import { createApplication } from 'graphql-modules' import { PubSub } from 'graphql-subscriptions' import { myModule } from './my-module' const application = createApplication({ modules: [myModule /* ... */], providers: [ { provide: PubSub, useValue: new PubSub() } ] }) ``` -------------------------------- ### Load SDL from .graphql Files Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/type-definitions.mdx Store your GraphQL SDL in `.graphql` files and import them directly into your module. This helps keep your schema organized and separate from your business logic. ```typescript import MyQueryType from './query.type.graphql' import { createModule } from 'graphql-modules' export const myModule = createModule({ id: 'my-module', dirname: __dirname, typeDefs: [MyQueryType] }) ``` -------------------------------- ### Dynamically Load SDL Files Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/type-definitions.mdx Use `@graphql-tools/load-files` to dynamically load multiple SDL files from a directory. This is useful when you have a large number of schema files. ```bash npm i @graphql-tools/load-files ``` ```typescript import MyQueryType from './query.type.graphql' import { createModule } from 'graphql-modules' import { loadFilesSync } from '@graphql-tools/load-files' import { join } from 'node:path' export const myModule = createModule({ id: 'my-module', dirname: __dirname, typeDefs: loadFilesSync(join(__dirname, './typeDefs/*.graphql')) }) ``` -------------------------------- ### Registering Middleware for All Fields of All Types Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/advanced/middlewares.mdx Use double `*` wildcards to apply a middleware globally to all fields across all types. ```json { "*": { "*": [yourMiddleware] } } ``` -------------------------------- ### Resolvers Composition (V0) vs Middleware (V1) Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/recipes/migration.mdx Demonstrates the API changes for defining and using resolver wrappers, moving from `resolversComposition` in v0 to `middlewares` in v1. ```typescript function yourMiddleware({ root, args, context, info }, next) { /* code */ return next() } const myModule = createModule({ // ... middlewares: { Query: { me: [yourMiddleware] } } }) ``` ```typescript export const yourMiddleware = () => next => async (root, args, context, info) => { /* code */ return next(root, args, context, info) } const myModule = new GraphQLModule({ /*...*/ resolversComposition: { 'Query.me': [yourMiddleware] } }) ``` -------------------------------- ### Test a Module Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/testing.mdx Use `testkit.testModule` to create an application specifically for testing a single module. This function calls `createApplication` internally and offers helpful options. Ensure `reflect-metadata` is imported. ```typescript import 'reflect-metadata' import { testkit } from 'graphql-modules' import { myModule } from './my-module' test('ing', () => { const app = testkit.testModule(myModule) expect(app.schema.getQueryType()).toBeDefined() }) ``` -------------------------------- ### Import Testkit Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/testing.mdx Import the `testkit` object from the `graphql-modules` package to access testing utilities. ```typescript import { testkit } from 'graphql-modules' ``` -------------------------------- ### Registering Middleware for All Fields of a Type Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/advanced/middlewares.mdx Use the `*` wildcard to apply a middleware to all fields of a given type (e.g., `Query`). ```json { "Query": { "*": [yourMiddleware] } } ``` -------------------------------- ### V0 Module Configuration Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/recipes/migration.mdx This is the V0 approach to module configuration, using `GraphQLModule` with a generic type for configuration. ```typescript import { GraphQLModule } from '@graphql-modules/core' export interface MyModuleConfig { secretKey: string remoteEndpoint: string someDbInstance: SomeDBInstance } // You can access the config object like below inside the module declaration export const MyModule = new GraphQLModule({ providers: ({ config: { someDbInstance } }) => [ MyProvider, { provide: SomeDbInstance, useValue: someDbInstance } ] }) ``` ```typescript @Injectable() export class MyProvider { constructor(@Inject(ModuleConfig) private config: MyModuleConfig) { // ... } } ``` -------------------------------- ### Consuming a Global Provider Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/di/providers.mdx Demonstrates how a module (Posts) can consume a globally provided service (Auth). Even though Auth is global, it uses the injector it was created with, ensuring isolation. ```typescript // Posts module @Injectable() export class Posts { constructor( private auth: Auth, private logger: Logger ) {} getMyPosts() { const me = this.auth.getCurrentUser() logger.debug(`Asking for my posts`) // ... } } ``` -------------------------------- ### TypeDefs: DocumentNode vs String Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/recipes/migration.mdx Illustrates the change in how `typeDefs` are handled, requiring `DocumentNode` (via `gql`) in v1, whereas v0 accepted plain strings. ```typescript import { gql, createModule } from 'graphql-modules' const myModule = createModule({ // ... typeDefs: gql` type Query { foo: String } ` }) ``` ```typescript const myModule = GraphQLModule({ // ... typeDefs: `type Query { foo: String }` }) ``` -------------------------------- ### Registering Middlewares in an Application Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/advanced/middlewares.mdx Configure middlewares at the application level using the `middlewares` option during `createApplication`. ```typescript import { createApplication } from 'graphql-modules' const application = createApplication({ // ... middlewares: { Query: { me: [myMiddleware] } } }) ``` -------------------------------- ### Overwrite Application Providers for Testing Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/testing.mdx Use `testkit.mockApplication` and `addProviders` to overwrite application-level providers for testing. Providers at the end of the list take precedence. ```typescript import 'reflect-metadata' import { testkit } from 'graphql-modules' import { application, ENVIRONMENT } from './application' test('ing', () => { const app = testkit.mockApplication(application).addProviders([ { provide: ENVIRONMENT, useValue: 'testing' } ]) expect(app.schema.getQueryType()).toBeDefined() }) ``` -------------------------------- ### createModule Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/api.mdx Creates a Module, which is a fundamental building block for an Application. Accepts a `ModuleConfig` object. ```APIDOC ## createModule Creates a Module, an element used by Application. Accepts `ModuleConfig`. ```ts import { createModule, gql } from 'graphql-modules' export const usersModule = createModule({ id: 'users', typeDefs: gql` // GraphQL SDL `, resolvers: { // ... } }) ``` ``` -------------------------------- ### Implement Authentication Middleware Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/testing.mdx This code defines an `AuthProvider` service that checks the login status from the operation context. The `authMiddleware` function uses this provider to protect the `Query.me` field, throwing an error if the user is not logged in. ```typescript import { Injectable, Inject, Scope, CONTEXT } from 'graphql-modules' @Injectable({ scope: Scope.Operation }) export class AuthProvider { constructor(@Inject(CONTEXT) private context: { isLoggedIn: boolean }) {} isLoggedIn() { return this.context.isLoggedIn === true } } async function authMiddleware({ context }, next) { if (!context.injector.get(AuthProvider).isLoggedIn()) { throw new Error('Not logged in') } return next() } ``` -------------------------------- ### Explicit Class Provider Configuration Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/di/providers.mdx Manually configure a class provider using `useClass` for explicit control. ```typescript { provide: Data, useClass: Data } ``` -------------------------------- ### DataLoader as a Service with GraphQL Modules Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/recipes/dataloader.mdx Demonstrates how to configure DataLoader as a provider within a GraphQL Module. It uses `Scope.Operation` and a factory function to create a DataLoader instance that batches user data retrieval. The DataLoader is then injected into a resolver to fetch user data by ID. ```typescript import { createModule, Scope, InjectionToken } from 'graphql-modules' import DataLoader from 'dataloader' export const USER_DATA_LOADER = new InjectionToken('USER_DATA_LOADER') export const myModule = createModule({ providers: [ { provide: USER_DATA_LOADER, scope: Scope.Operation, useFactory: () => new DataLoader(keys => myBatchGetUsers(keys)) } ], resolvers: { Query: { getUserById(root, args, context) { return context.injector.get(USER_DATA_LOADER).load(args.id) } } } }) ``` -------------------------------- ### Authentication Module Schema Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/index.mdx Extends the Query and User types and defines mutations for login and signup. ```graphql extend type Query { me: User } type Mutation { login(username: String!, password: String!): User signup(username: String!, password: String!): User } extend type User { username: String! } ``` -------------------------------- ### Module Implementation with Subscriptions Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/advanced/subscriptions.mdx Implement a GraphQL module that sends and subscribes to events using `PubSub`. The `Messages` service publishes events when a message is sent, and the `Subscription.messageAdded` resolver subscribes to these events. ```typescript import { createModule, Injectable, gql } from 'graphql-modules' import { PubSub } from 'graphql-subscriptions' const MESSAGE_ADDED = 'MESSAGE_ADDED' const messages = [ // ... ] @Injectable() class Messages { constructor(private pubsub: PubSub) {} async all() { return messages } async send(body: string) { const message = { id: generateRandomId(), body } messages.push(message) this.pubsub.publish(MESSAGE_ADDED, { messageAdded: message }) return message } } export const myModule = createModule({ id: 'my-module', providers: [Messages], typeDefs: gql` type Query { messages: [Message!]! } type Mutation { sendMessage(message: String!): Message! } type Subscription { messageAdded: Message } type Message { id: ID! body: String! } `, resolvers: { Query: { messages(parent, args, ctx: GraphQLModules.Context) { return ctx.injector.get(Messages).all() } }, Mutation: { sendMessage(parent, { message }, ctx: GraphQLModules.Context) { return ctx.injector.get(Messages).send(message) } }, Subscription: { messageAdded: { subscribe(root, args, ctx: GraphQLModules.Context) { return ctx.injector.get(PubSub).asyncIterator([MESSAGE_ADDED]) } } } } }) ``` -------------------------------- ### Gallery Module Schema Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/index.mdx Declares the Image type and extends the User and Mutation types for gallery functionality. ```graphql type Image { id: ID! url: String! user: User! } extend type User { gallery: [Image] } extend type Mutation { uploadPicture(image: File!): Image } ``` -------------------------------- ### Import Statements: V1 vs V0 Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/recipes/migration.mdx Compares the import statements required for v1 (single package) and v0 (separate core and di packages). ```typescript import { gql, createModule, Injectable } from 'graphql-modules' ``` ```typescript import { GraphQLModule } from '@graphql-modules/core' import { Injectable } from '@graphql-modules/di' import gql from 'graphql-tag' ``` -------------------------------- ### Manual Operation Lifecycle Control with OperationController Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/advanced/lifecycles.mdx Demonstrates using `OperationController` to manually manage the lifecycle of operation-scoped injectors, allowing access to services before execution and custom destruction. ```typescript @Injectable({ scope: Scope.Operation }) class Status { enabled = true enable() { this.enabled = true } disable() { this.enabled = false } } const mod = createModule({ id: 'status', providers: [Status] }) const app = createApplication({ modules: [mod], providers: [Data] }) server.use('/graphql', (req, res) => { const controller = app.createOperationController({ /* It's important to pass a correct context value here. This value represents a context object available in Dependency Injection. Keep in mind, it doesn't have to be the same context object as your resolvers get. */ context: {} }) const status = controller.injector.get(Status) if (process.env.NODE_ENV === 'production') { status.disable() } // < graphql execution here > controller.destroy() }) ``` -------------------------------- ### Replace Module Providers for Testing Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/testing.mdx Use `testkit.mockApplication`, `replaceModule`, and `testkit.mockModule` to modify a module and overwrite its providers for testing purposes. Ensure `reflect-metadata` is imported. ```typescript import 'reflect-metadata' import { testkit } from 'graphql-modules' import { application } from './application' import { myModule, ENVIRONMENT } from './my-module' test('ing', () => { const app = testkit.mockApplication(application).replaceModule( testkit.mockModule(myModule, { providers: [ { provide: ENVIRONMENT, useValue: 'testing' } ] }) ) expect(app.schema.getQueryType()).toBeDefined() }) ``` -------------------------------- ### Registering Middleware for a Specific Field Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/advanced/middlewares.mdx Apply a middleware to a single field (`me`) on a specific type (`Query`). ```json { "Query": { "me": [yourMiddleware] } } ``` -------------------------------- ### Injection Tokens Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/api.mdx Provides details on Injection Tokens used for dependency injection within GraphQL Modules. ```APIDOC ## CONTEXT `CONTEXT` is an InjectionToken representing the provided `GraphQLModules.GlobalContext` ```ts import { CONTEXT, Inject, Injectable } from 'graphql-modules' @Injectable() export class Data { constructor(@Inject(CONTEXT) private context: GraphQLModules.GlobalContext) {} } ``` ## MODULE_ID `MODULE_ID` is an InjectionToken representing module's ID ```ts import { MODULE_ID, Inject, Injectable } from 'graphql-modules' @Injectable() export class Data { constructor(@Inject(MODULE_ID) moduleId: string) { console.log(`Data used in ${moduleId} module`) } } ``` ``` -------------------------------- ### Defining a Global Provider Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/di/providers.mdx Illustrates how to define a service (Auth) as a globally available provider by setting the `global` option to `true` in the `@Injectable` decorator. Global providers are accessible by other modules but remain isolated to their original injector. ```typescript // Users module @Injectable({ global: true }) export class Auth { constructor(private logger: Logger) {} getCurrentUser() { logger.debug(`Asking for authenticated user`) // ... } } ``` -------------------------------- ### Define a GraphQL Module Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/testing.mdx This snippet defines a basic GraphQL module with a `Query` type, a `User` type, and a resolver for the `me` query. It also includes a provider and applies a middleware to the `Query.me` field. ```typescript import { createModule, gql } from 'graphql-modules' import { AuthProvider, authMiddleware } from './auth' export const myModule = createModule({ id: 'my-module', typeDefs: gql` type Query { me: User } type User { name: String } `, resolvers: { Query: { me() { return { name: 'Bob' } } } }, providers: [AuthProvider], middleware: { Query: { me: [authMiddleware] } } }) ``` -------------------------------- ### Creating a GraphQL Module Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/api.mdx Define a reusable GraphQL module with its own type definitions, resolvers, and providers. Modules are the building blocks of a GraphQL application. ```typescript import { createModule, gql } from 'graphql-modules' export const usersModule = createModule({ id: 'users', typeDefs: gql` // GraphQL SDL `, resolvers: { // ... } }) ``` -------------------------------- ### Integrate with Apollo Server Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/get-started.mdx Use `createApolloExecutor` to create an executor adapted for Apollo Server. This ensures seamless integration. ```typescript import { ApolloServer } from 'apollo-server' import { application } from './application' const executor = application.createApolloExecutor() const schema = application.schema const server = new ApolloServer({ schema, executor }) server.listen().then(({ url }) => { console.log(`🚀 Server ready at ${url}`) }) ``` -------------------------------- ### Execute Operations with Test Module Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/testing.mdx Utilize `testkit.execute` to test the entire execution flow of your module. This helper simplifies operation execution by internally managing application creation and schema handling. ```typescript import 'reflect-metadata' import { testkit, gql } from 'graphql-modules' import { myModule, UsersProvider } from './my-module' test('ing', () => { const app = testkit.testModule(myModule, { providers: [ { provide: UsersProvider, useValue: { getCurrentUser() { return { name: 'Bob' } } } } ] }) const result = testkit.execute(app, { document: gql` { me { name } } ` }) expect(result.data.me.name).toEqual('Bob') }) ``` -------------------------------- ### Implementing Access Control with Exceptions Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/advanced/middlewares.mdx Throw an error within a middleware to prevent access if certain conditions (e.g., authentication) are not met. ```typescript async function middleware({ root, args, context, info }, next) { if (!context.injector.get(Auth).isLoggedIn()) { throw new Error('Not logged in') } return next() } ``` -------------------------------- ### User Module Schema Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/index.mdx Defines the basic fields for a User type and a query to fetch a user by ID. ```graphql type Query { user(id: ID!): User } type User { id: ID! email: String! } ``` -------------------------------- ### Profile Module Schema Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/index.mdx Declares the Profile type and adds a profile field to the User type. ```graphql type Profile { age: Int! name: String! } extend type User { profile: Profile! } ``` -------------------------------- ### Registering Middlewares in a Module Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/advanced/middlewares.mdx Define middlewares within the `middlewares` configuration when creating a `graphql-modules` module. ```typescript import { createModule } from 'graphql-modules' const myModule = createModule({ // ... middlewares: { Query: { me: [myMiddleware] } } }) ``` -------------------------------- ### Integrate with Express GraphQL Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/get-started.mdx Provide the custom `execute` function from your application to `express-graphql` via the `customExecuteFn` option. ```typescript import express from 'express' import graphqlHTTP from 'express-graphql' import { application } from './application' const execute = application.createExecution() const schema = application.schema const server = express() server.use( '/', graphqlHTTP({ schema, customExecuteFn: execute, graphiql: true }) ) server.listen(4000, () => { console.log(`🚀 Server ready at http://localhost:4000/`) }) ``` -------------------------------- ### Import Other Modules into Test Application Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/testing.mdx Include other modules in the tested application using the `modules` option in `testkit.testModule`. This option accepts an array of modules and functions similarly to `createAppliction({ modules: [...] })`. ```typescript import 'reflect-metadata' import { testkit } from 'graphql-modules' import { myModule } from './my-module' import { otherModule } from './other-module' test('ing', () => { const app = testkit.testModule(myModule, { modules: [otherModule] }) }) ``` -------------------------------- ### Value Provider Expression Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/di/providers.mdx Configure a value provider using `provide` and `useValue`. ```typescript { provide: ApiKey, useValue: 'my-api-key' } ``` -------------------------------- ### Check Provider Scope with readProviderOptions Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/testing.mdx Verify the scope of providers using `testkit.readProviderOptions`. This is useful for ensuring singleton providers behave as expected. ```typescript import 'reflect-metadata' import { testkit, Scope } from 'graphql-modules' import { Logger } from './logger' test('ing', () => { const options = testkit.readProviderOptions(Logger) expect(options.scope).toEqual(Scope.Singleton) }) ``` -------------------------------- ### Lazy Loading with forwardRef Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/di/providers.mdx Explains how to use `forwardRef` to resolve circular dependencies between modules or services by allowing references to be defined before they are fully initialized. This is crucial when dealing with interdependent components. ```typescript import { Injectable, Inject } from 'graphql-modules' import { ApiKey } from './keys' @Injectable() class Posts { constructor(@Inject(forwardRef(() => ApiKey)) private key: string) {} allPosts() { if (!this.key) { throw new Error('API key is required') } return [ // ... ] } } ``` -------------------------------- ### Injecting a Dependency with @Inject Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/di/providers.mdx Shows how to use the @Inject decorator to inject a dependency (ApiKey) into a class constructor. This is necessary due to TypeScript's type system limitations. ```typescript import { Injectable, Inject } from 'graphql-modules' import { ApiKey } from './keys' @Injectable() class Posts { constructor(@Inject(ApiKey) private key: string) {} allPosts() { if (!this.key) { throw new Error('API key is required') } return [ // ... ] } } ``` -------------------------------- ### Consuming InjectionToken in a Resolver Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/di/providers.mdx Demonstrates how to access an InjectionToken within a GraphQL resolver using the context's injector. Ensure the Injector is available in the GraphQL Context. ```typescript import { ApiKey } from './keys' const resolvers = { Query: { me(parent, args, context, info) { const apiKey = context.injector.get(ApiKey) if (!this.key) { throw new Error('API key is required') } return auth.getCurrentUser() } } } ``` -------------------------------- ### Extend Module Schema with typeDefs and resolvers Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/testing.mdx When `replaceExtensions` is insufficient, `testkit.testModule` allows providing additional `typeDefs` and `resolvers` to extend the module's schema. This approach can be combined with `replaceExtensions`. ```typescript import 'reflect-metadata' import { testkit, gql } from 'graphql-modules' import { myModule } from './my-module' test('ing', () => { const app = testkit.testModule(myModule, { typeDefs: gql` type User { name: String } `, resolvers: { Query: { me() { return { name: 'Bob' } } } }, replaceExtensions: true }) expect(app.schema.getQueryType()).toBeDefined() }) ``` ```typescript import { createModule, gql } from 'graphql-modules' export const myModule = createModule({ id: 'my-module', typeDefs: gql` extend type Query { me: User } ` }) ``` -------------------------------- ### Register Value Provider in Module Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/di/providers.mdx Register a value provider in a module, associating a token with a specific value. ```typescript import { createModule } from 'graphql-modules' import { ApiKey } from './keys' export const myModule = createModule({ id: 'my-module', // ... providers: [ { provide: ApiKey, useValue: 'my-api-key' } ] }) ``` -------------------------------- ### Shared Injectables: Global Flag in V1 Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/recipes/migration.mdx Illustrates how v1 simplifies sharing injectables across modules using the `global: true` option in `@Injectable`, compared to v0's strict `imports` dependency. ```typescript // Module 1 @Injectable({ global: true }) class MyProvider { // ... } const moduleOne = createModule({ providers: [MyProvider] }) // Module 2 @Injectable() class MyOtherProvider { constructor(myProvider: MyProvider) { } } const moduleTwo = createModule({ ... }) ``` ```typescript // Module 1 @Injectable() class MyProvider { // ... } const moduleOne = new GraphQLModule({ providers: [MyProvider] }) // Module 2 @Injectable() class MyOtherProvider { constructor(myProvider: MyProvider) {} } const moduleTwo = new GraphQLModule({ imports: [moduleOne] }) const rootModule = new GraphQLModule({ imports: [moduleTwo] }) ``` -------------------------------- ### Access Service via Injector in Resolver Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/di/providers.mdx Retrieve a service instance from the GraphQL context's injector within a resolver. ```typescript import { Auth } from './auth' const resolvers = { Query: { me(parent, args, context, info) { const auth = context.injector.get(Auth) return auth.getCurrentUser() } } } ``` -------------------------------- ### Register Class Provider in Module Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/di/providers.mdx Include the injectable class in the `providers` array of a module to register it. ```typescript import { createModule } from 'graphql-modules' import { Data } from './data' export const myModule = createModule({ id: 'my-module', // ... providers: [Data] }) ``` -------------------------------- ### Register Factory Provider in Module Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/di/providers.mdx Register a factory provider in a module, allowing dynamic value creation based on dependencies. ```typescript import { createModule } from 'graphql-modules' import { ApiKey } from './keys' export const myModule = createModule({ id: 'my-module', // ... providers: [ { provide: ApiKey, useFactory(config: Config) { if (config.environment) { return 'my-api-key' } return null }, deps: [Config] } ] }) ``` -------------------------------- ### Injecting Context in a Class Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/context.mdx Use the CONTEXT token with GraphQL Modules' Dependency Injection to inject the global context into your classes. ```typescript import { CONTEXT, Inject, Injectable } from 'graphql-modules' @Injectable() export class Data { constructor(@Inject(CONTEXT) private context: GraphQLModules.GlobalContext) {} } ``` -------------------------------- ### Factory Provider Expression Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/di/providers.mdx Configure a factory provider with `useFactory` and specify its dependencies with `deps`. ```typescript { provide: ApiKey, useFactory(config: Config) { if (config.environment === 'production') { return 'my-api-key'; } return null; }, deps: [Config] } ``` -------------------------------- ### Calling the Next Middleware Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/advanced/middlewares.mdx The `next` function is used to invoke the subsequent middleware or the actual resolve function. ```typescript function middleware({ root, args, context, info }, next) { // code return next() } ``` -------------------------------- ### Singleton Scope Service Provider Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/di/scopes.mdx Defines a service with Singleton scope, which is the default. The service instance is created once and reused throughout the application's lifecycle. ```typescript import { Injectable, createModule } from 'graphql-modules' @Injectable() class Data {} export const myModule = createModule({ id: 'my-module', providers: [Data] // ... }) ``` -------------------------------- ### Test Module with replaceExtensions Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/testing.mdx Use the `replaceExtensions` option in `testkit.testModule` to transform type extensions into concrete type definitions for testing. This is useful when a module extends types like `Query` but doesn't depend on other modules. ```typescript import 'reflect-metadata' import { testkit } from 'graphql-modules' import { myModule } from './my-module' test('ing', () => { const app = testkit.testModule(myModule, { replaceExtensions: true }) expect(app.schema.getQueryType()).toBeDefined() }) ``` ```typescript import { createModule, gql } from 'graphql-modules' export const myModule = createModule({ id: 'my-module', typeDefs: gql` extend type Query { me: User } type User { id: ID } ` }) ``` -------------------------------- ### Accessing Execution Context in a Singleton Service Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/advanced/execution-context.mdx Use the `@ExecutionContext` decorator on a private property to inject the GraphQL context and injector into a Singleton service. This allows Singletons to access operation-scoped services and data. ```typescript import { Injectable, ExecutionContext } 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) } } ``` -------------------------------- ### Register Explicit Class Provider in Module Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/di/providers.mdx Register an explicitly configured class provider within a module's `providers` array. ```typescript import { createModule } from 'graphql-modules' import { Data } from './data' export const myModule = createModule({ id: 'my-module', // ... providers: [ { provide: Data, useClass: Data } ] }) ``` -------------------------------- ### Define Types with gql Tag Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/type-definitions.mdx Use the `gql` tag to define your GraphQL schema directly within your module. This provides syntax highlighting and better tooling support. ```typescript import { createModule, gql } from 'graphql-modules' export const myModule = createModule({ id: 'my-module', dirname: __dirname, typeDefs: gql` type Query { user(id: ID!): User } type User { id: ID! username: String! } ` }) ``` -------------------------------- ### Integrate with GraphQL Helix Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/get-started.mdx Use `processRequest` from `graphql-helix` and provide the custom `execute` and `subscribe` functions from your GraphQL Modules application. ```typescript import express from 'express' import { getGraphQLParameters, processRequest } from 'graphql-helix' import { application } from './application' const app = express() app.use(express.json()) app.use('/graphql', async (req, res) => { const request = { body: req.body, headers: req.headers, method: req.method, query: req.query } const { operationName, query, variables } = getGraphQLParameters(request) const result = await processRequest({ operationName, query, variables, request, schema: application.schema, execute: application.createExecution(), subscribe: application.createSubscription() }) result.headers.forEach(({ name, value }) => res.setHeader(name, value)) res.status(result.status) res.json(result.payload) }) app.listen(port, () => { console.log(`GraphQL server is running on port ${port}.`) }) ``` -------------------------------- ### Define Injection Token Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/di/providers.mdx Create an `InjectionToken` to represent a specific value or configuration. ```typescript import { InjectionToken } from 'graphql-modules' export const ApiKey = new InjectionToken('api-key') ``` -------------------------------- ### DataLoader within a Service using GraphQL Modules Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/recipes/dataloader.mdx Shows how to use DataLoader within an injectable service in GraphQL Modules. The `UserProvider` class uses `Scope.Operation` and injects `MyExternalDataProvider` to fetch user data. A DataLoader instance is created internally to batch requests for user data by ID. ```typescript import { Injectable, Scope } from 'graphql-modules' import DataLoader from 'dataloader' import { MyExternalDataProvider } from './my-external-data-provider' @Injectable({ scope: Scope.Operation }) export class UserProvider { private dataLoader = new DataLoader(keys => this.myDataProvider.findUsers(keys) ) constructor(private myDataProvider: MyExternalDataProvider) {} getUserById(userId: string) { return this.dataLoader.load(userId) } } ``` -------------------------------- ### Automatic Operation Destruction with autoDestroy Flag Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/advanced/lifecycles.mdx Illustrates enabling `autoDestroy` on `OperationController` to automatically clean up operation-scoped injectors after GraphQL execution, removing the need for manual `controller.destroy()` calls. ```typescript const controller = app.createOperationController({ context: {}, autoDestroy: true }) // no need to call `controller.destroy()` now ``` -------------------------------- ### Configure GraphQL Code Generator for Context Type Source: https://github.com/graphql-hive/graphql-modules/blob/master/website/src/content/essentials/type-safety.mdx Specify your extended context type in the GraphQL Code Generator configuration to ensure generated types align with your application's context. ```yaml schema: './src/modules/*.graphql' generates: ./src/modules/: preset: graphql-modules config: contextType: 'GraphQLModules.Context' # Your extended context type! presetConfig: baseTypesPath: ../generated/schema-types.ts filename: generated/module-types.ts plugins: - typescript - typescript-resolvers # ... ```