Nicholas Porter
Nicholas Porter

Reputation: 2951

TypeScript add custom Request header in Express

I am trying to add a custom header to my request, but it must be modified/implemented in the interface.

The default Request interface references IncomingHttpHeaders. So I am attempting to extend this interface with my own custom token header.

import { IncomingHttpHeaders } from 'http';

declare module 'express-serve-static-core' {
    interface IncomingHttpHeaders {
        "XYZ-Token"?: string
    }
}

I have updated my .tsconfig file to read the ./types folder. The name of my file is index.d.ts

I can successfully compile the code if I do not use my custom header, but when I try to reference the token header in the code I get the following compilation error:

Error

error TS2538: Type 'string[]' cannot be used as an index type.

    req.headers['XYZ-Token']

If I use any of the values of the original interface everything works fine.

Example:

    req.headers['user-agent']

Additional information: I am using NestJS, which uses Fastify/Express under the hood. I can confirm that the Request interface being used is from Express. Fastify is backwards compatible with all Express modules. Mainly using Fastify because it's faster.

Upvotes: 13

Views: 17749

Answers (3)

Felipe Aguiar
Felipe Aguiar

Reputation: 21

I faced a problem like this recently, and the solution that worked for me was creating a type that extends from IncomingHttpHeaders

import { IncomingHttpHeaders } from "http2";

interface MyCustomsHearders {
    foo: "bar";
}

type IncomingCustomHeaders = IncomingHttpHeaders & MyCustomsHearders;
const { foo } = req.headers as IncomingCustomHeaders;

I know it's not quite the most "formal" way to solve the problem, but it worked fine for me.

Upvotes: 0

Nicholas Porter
Nicholas Porter

Reputation: 2951

Looks like the wrong module name is in the declaration.

Even though the IncomingHttpHeaders interface is being attached to the Request object from express-serve-static-core, the original source of the IncomingHttpHeaders interface is actually part of the http package.

The following allowed the custom header to be accessible in the code and ts compiled correctly.

import { IncomingHttpHeaders } from 'http';

declare module 'http' {
    interface IncomingHttpHeaders {
        "XYZ-Token"?: string
    }
}

Upvotes: 21

Jay McDoniel
Jay McDoniel

Reputation: 70191

For whatever reason, it thinks the string you are passing in is an array, but besides that point, if you need to set a custom header (and it is not a dynamic value) you can use the @Header() decorator. If it is dynamic then you can use an interceptor to grab the response pre-flight and set the header there with something like

@Injectable()
export class CustomHeaderInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next
      .handle()
      .pipe(
        tap(() => context.switchToHttp().getResponse().header('XYZ-Token', customValue),
      );
  }
}

Upvotes: 0

Related Questions