Feathers.js Request Id Middleware
Tags: feathersjs, typescript, middleware, express
Published: 2021-10-31 06:52:07

## Prepare your project

1. Generate the app (if you don't have existing app), please see [here](https://docs.feathersjs.com/guides/basics/generator.html). Basically you need to install the generator with: `npm install @feathersjs/cli -g`

2. You can follow the step-by-step in the generate app page. Some notes: I use Typescript for the codebase.

## Generate and write the Middleware

* Use `feathers generate middleware`. You can see how I generate the middleware here.

![Generate Middleware](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nmslep85l3zfneko1gjh.png)
 
* I want to use `uuidv4` as my request id. So please install the uuid use: `npm install uuid @types/uuid` or `yarn install uuid @types/uuid` (if you use yarn).

* Write the middleware. We put the requestId at feathers object. You can found the file at `src/middleware/request-id.ts`.

```ts
import { v4 as uuidv4 } from 'uuid';
import { Request, Response, NextFunction } from 'express';

export default () => {
  // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/explicit-module-boundary-types
  return (req: Request, res: Response, next: NextFunction) => {
    const requestId= uuidv4();
    if (!req.feathers) {
      req.feathers = {};
    }
    req.feathers.requestId = requestId;
    next();
  };
};
```

* Update log hooks for capture our `requestId`. I update the `src/hooks/log.ts`.

```ts
// A hook that logs service method before, after and error
// See https://github.com/winstonjs/winston for documentation
// about the logger.
import logger from '../logger';
import util from 'util';
import { HookContext, Hook } from '@feathersjs/feathers';

// To see more detailed messages, uncomment the following line:
logger.level = 'debug';

export default function (): Hook {
  return (context: HookContext) => {
    const { params } = context;
    const requestId = params.requestId;
    logger.debug(`Request Id: ${requestId}`);
    // This debugs the service call and a stringified version of the hook context
    // You can customize the message (and logger) to your needs
    logger.debug(
      `${context.type} app.service('${context.path}').${context.method}()`,
    );

    if (
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      typeof (context as any).toJSON === 'function' &&
      logger.level === 'debug'
    ) {
      logger.debug('Hook Context', util.inspect(context, { colors: false }));
    }

    if (context.error && !context.result) {
      logger.error(context.error.stack);
    }
  };
}
```

![Log request id](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gc7dx6v9ud3so67s20bh.png)
 
* I want to use error handler and bring the request id. First I will disable html output for error handler. Because I don't want to handle HTML output. You can update the `src/app.ts` like this.

```ts
// another code...

// Configure a middleware for 404s and the error handler
app.use(express.notFound());
app.use(express.errorHandler({ html: false }));

app.hooks(appHooks);

export default app;
```

* Generate application wide error hooks. You can see picture below. For more information. You can check [this](https://docs.feathersjs.com/api/errors.html#error-handling).

![Application Wide hook error](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tpzlzc34tk1c94npht9w.png)
 
* Write the hooks. You can found at `src/hooks/common-error.ts`. 

```ts
// Use this hook to manipulate incoming or outgoing data.
// For more information on hooks see: http://docs.feathersjs.com/api/hooks.html
import { Hook, HookContext } from '@feathersjs/feathers';

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export default (options = {}): Hook => {
  return async (context: HookContext): Promise<HookContext> => {
    if (context.error) {
      console.log(context);
      const { params } = context;
      const requestId = params.requestId;
      const requestIdObject = {
        requestId,
      };
      context.error.errors = Object.assign(
        context.error.errors,
        requestIdObject,
      );
    }
    return context;
  };
};
```

* After we write that, we will see the `requestId` under errors property like this. This will help to trace the error.

![Example Error use requestId](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aew45l03l09rl1o38sne.png)

## Thank you

That is it. If you have another suggestions. Please feel free to comment here.

Thank you. :)

![Thank you](https://media.giphy.com/media/osjgQPWRx3cac/giphy.gif)