Catch the highlights of GraphQLConf 2023! Click for recordings. Or check out our recap blog post.
Docs
Advanced
Lifecycles

Lifecycles

Lifecycle Hooks

There are two life cycle hooks in GraphQL Modules, one represents an incoming request and the other is called when the execution is done. Hooks are only available in Operation scoped Injector.

Every Operation scoped service is created for each ongoing GraphQL operation, which means you can use the constructor as the initial hook.

After the Operation is resolved and the context is about to be destroyed, GraphQL Modules call the onDestroy method on all operation-scoped services.

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
  }
}

Manual Control of Operation Cycle

As you know, GraphQL operation represents an incoming request with GraphQL query and variables meaning it ends when GraphQL API resolves data and sends back the response. An operation is created when GraphQL execution starts (execute function call). With operation comes Operation-scoped Dependency Injection.

In some cases you wish to:

  • access operation-scoped services before the execution phase happens
  • destroy a session and operation-scoped injectors sometime after the execution phase

This is why OperationController exists - it allows to fully control the life of the operation-scoped injectors.

Here's an example:

@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()
})

autoDestroy

Using OperationController means you're in charge of the operation flow, and you need to destroy the session manually by default.

To improve the developer experience, we decided to introduce autoDestroy flag that automatically destroys the session right after the GraphQL execution phase ends, exactly like without an OperationController.

const controller = app.createOperationController({
  context: {},
  autoDestroy: true
})
 
// no need to call `controller.destroy()` now
💡

Keep in mind that using autoDestroy means the controller completes its job immediately after the execution phase and everything is cleaned up.