Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I handle type with middleware of express?

I am using Typescript in Node.js. When you use Express middleware, you often transform the Request object. With Typescript, however, we could not track how the Request object was transformed. If you know the middleware that passed before, is there a way to find out the type of the request from it? If not possible in express, I would like to find another framework where it is possible. Is it possible in Nest (https://github.com/kamilmysliwiec/nest)?

Example Code

import { Request, Response, NextFunction } from 'express';

function userMiddleware(req: Request & User, res: Response, next: NextFunction) {
    req.user = {
        id: 'user_id',
    };
    next();
}

interface User {
    user: {
        id: string;
    }
}

interface Middleware {
    <T>(req: Request & T, res: Response, next: NextFunction): void;
}

class Controller {
    middleware = [userMiddleware];

    get = new GetMethod(this.middleware);

    post = (req: Request /* I don't know exact req type */, res: Response, next: NextFunction) => {
        console.log(req.user) // Error!
    }
}

class GetMethod {
    constructor(middleware: Middleware[]) {
        // How to deduce type of req from Middleware array?
    }
}

const controller = new Controller();

express.use('/', controller.middleware, controller.post);

I want to extract type information from Middleware list in Controller class.

like image 819
Yoshi Avatar asked Apr 15 '17 18:04

Yoshi


People also ask

How does Express handle middleware?

Express middleware are functions that execute during the lifecycle of a request to the Express server. Each middleware has access to the HTTP request and response for each route (or path) it's attached to. In fact, Express itself is compromised wholly of middleware functions.

What is the middleware in Express and its types?

Middleware functions in Express are of the following types: Application-level middleware which runs for all routes in an app object. Router level middleware which runs for all routes in a router object. Built-in middleware provided by Express like express.

Which middleware is used to handle the routing logic in Express?

Router-level middleware works in the same way as application-level middleware, except it is bound to an instance of express.Router() . Load router-level middleware by using the router.use() and router.METHOD() functions.

What is the point of middleware in Express?

An Express-based application is a series of middleware function calls. Advantages of using middleware: Middleware can process request objects multiple times before the server works for that request. Middleware can be used to add logging and authentication functionality.


1 Answers

First I think the right interface is

interface User {
  id: string;
}

Because they're callbacks they'll receive default Request that don't have user in its signature.

Therefore you have 2 options, do a type assertion, or to write a custom declaration. Both a fine if you do them properly.


Type assertion:

interface User {
  id: string;
}

const isObject = (value: unknown): value is {[key: string]: unknown} => {
  return value && typeof value === 'object';
};

const isReqWithUser = (req: Request): req is Request & {user: User} => {
  return isObject(req) && !!req.user;
}

class Controller {
  post = (req: Request, res: Response, next: NextFunction) => {
    if (isReqWithUser(req)) {
      console.log(req.user) // now it works
    }
    next();
  }
}

Custom declaration:

but we need to understand that user not always exist on the request and we should mark it optional.

interface User {
  id: string;
}

declare module 'express' {
  export interface Request {
    user?: User; // adding our custom declaration.
  }
}

class Controller {
  post = (req: Request, res: Response, next: NextFunction) => {
    console.log(req.user) // now it works
    next();
  }
}
like image 145
satanTime Avatar answered Oct 13 '22 05:10

satanTime