@fastify/request-context

repository·main·Indexed 41 days ago

https://github.com/fastify/fastify-request-context

A Fastify plugin providing request-scoped storage based on Node.js AsyncLocalStorage, with fallback to cls-hooked for older Node versions. It allows developers to persist data throughout the lifecycle of a single HTTP request using .get(), .set(), and .getStore() without passing objects through every function call. Version 7.0.0.

Tokens
1.9K
Snippets
7
Records
8
Agent score
3%

What's inside fastify-request-context

  1. How to access and manage request context

    main

    The request context (providing .get(), .set(), and .getStore()) is available in three ways:

    1. Via the library singleton: Import requestContext directly. This singleton retains the same request-scoped values as the decorators.
    2. Via the request object: Access req.requestContext within handlers or hooks.
    3. Via decorators: Access fastify.requestContext on the app instance, or this.requestContext within route handlers (when using standard function syntax).

    Use .set(key, value) to store data and .get(key) to retrieve it. Use .getStore() to retrieve the entire store object.

    const { fastifyRequestContext, requestContext } = require('@fastify/request-context')
    const fastify = require('fastify');
    
    const app = fastify();
    app.register(fastifyRequestContext);
    
    app.get('/', (req, reply) => {
      // 1. Using the library singleton
      const user = requestContext.get('user');
    
      // 2. Using the request decorator
      const store = req.requestContext.getStore();
    
      // 3. Using the app instance decorator
      const appUser = app.requestContext.get('user');
    
      reply.send({ user, store });
    });
  2. Type the request context in TypeScript

    main

    To get type safety for your context values, augment the @fastify/request-context module by defining the RequestContextData interface. This allows requestContext.get(key) to return the correct type for your specific keys.

    import { requestContext } from '@fastify/request-context'
    
    declare module '@fastify/request-context' {
      interface RequestContextData {
        foo: string
      }
    }
    
    // Type is 'string' (or 'string | undefined' with strictNullChecks: true)
    const foo = requestContext.get('foo')
  3. Use request context outside of an HTTP request

    main

    If you need to use code that depends on requestContext in environments without an active HTTP request (such as unit tests or background workers), wrap the execution in asyncLocalStorage.run() provided by the library.

    import { asyncLocalStorage, requestContext } from '@fastify/request-context';
    
    // In a test or worker
    await asyncLocalStorage.run({}, async () => {
      requestContext.set('userId', 'some-fake-user-id');
      // Any code called here can access 'userId' via requestContext.get()
      someCodeThatUsesRequestContext(); 
    });
  4. Configure @fastify/request-context plugin options

    main

    When registering the plugin, you can provide an options object to customize its behavior.

    Available options:

    • hook: Specifies the Fastify lifecycle hook where request context initialization is bound. Default is onRequest. Note: If using body parsers or EventEmitter-based plugins like @fastify/multipart, you may need to bind to a later hook like preValidation to ensure the context is maintained after parsing events.
    • defaultStoreValues: Sets initial values for the store. This can be an object or a function that receives the request object and returns an object.
    • createAsyncResource: A factory function that creates an extended AsyncResource object.
    const { fastifyRequestContext } = require('@fastify/request-context')
    const fastify = require('fastify');
    
    fastify.register(fastifyRequestContext, {
      hook: 'preValidation',
      defaultStoreValues: request => ({
        log: request.log.child({ foo: 123 })
      }),
      createAsyncResource: (req, context) => new MyCustomAsyncResource('type', req.id, context.user.id)
    });
  5. Register @fastify/request-context plugin

    main

    To enable request-scoped storage in your Fastify application, register the @fastify/request-context plugin. This plugin decorates the Fastify instance with requestContext and the Fastify request object with requestContext to allow accessing and managing scoped data.

    const fastify = require('fastify')()
    const requestContext = require('@fastify/request-context')
    
    fastify.register(requestContext)
    
    fastify.get('/', async (request, reply) => {
      // Access the context via the request object
      request.requestContext.set('user', { id: 1 })
      return { user: request.requestContext.get('user') }
    })
  6. Configure @fastify/request-context options

    main

    When registering the plugin, you can pass an opts object to customize its behavior:

    • hook: The Fastify hook used to initialize the context. Defaults to 'onRequest'. Supported values include 'onRequest' or 'preParsing'. Note that if you use a hook other than onRequest or preParsing, the plugin automatically adds a preValidation hook to ensure the async context is preserved through the lifecycle.
    • defaultStoreValues:
      • If a function: It is called with the request object and its return value is used as the initial store. This allows for dynamic default values based on the request.
      • If an object: This object is used as the initial store.
    • createAsyncResource: A function used to create a custom AsyncResource. It receives (req, requestContext) as arguments. If not provided, a default AsyncResource named 'fastify-request-context' is used.
  7. Use requestContext API to manage scoped data

    main

    The requestContext object provides methods to interact with the asynchronous local storage associated with the current request. It can be accessed via fastify.requestContext or request.requestContext.

    • get(key): Retrieves the value associated with the provided key from the current request's store. Returns undefined if the key does not exist or if there is no active store.
    • set(key, value): Sets the value for the provided key in the current request's store.
    • getStore(): Returns the entire store object for the current request.
    // Inside a route handler or hook
    const context = request.requestContext
    
    // Setting a value
    context.set('requestId', 'abc-123')
    
    // Getting a value
    const id = context.get('requestId')
    
    // Accessing the full store
    const store = context.getStore()