next.js 覆盖下一个连接中间件中的请求类型

s6fujrry  于 2023-08-04  发布在  其他
关注(0)|答案(2)|浏览(101)

我正在使用next-connect和next.js & typescript,我想创建一个中间件,向请求对象添加一些字段并推断新的请求类型。代码如下:

// multipart middleware
export type NextApiRequestMultipart = NextApiRequest & {
  files: Files;
  fields: Fields;
};
export function multipart(
  config?: Options
) {
  return async (
    req: NextApiRequest,
    res: NextApiResponse,
    next: NextHandler
  ) => {
    const { files, fields } = await parseForm(req, config);
    (req as NextApiRequestMultipart).files = files;
    (req as NextApiRequestMultipart).fields = fields;
    return next();
  };
}

个字符
StackBlitz存储库:see code

nukf8bse

nukf8bse1#

我设法将其作为示例解决方案来实现。以下是代码演示:stakc-blitz modified

方法的示例说明

我还没有测试过,但我想展示一下这种方法。
我们需要一个控制器路由器建设者这样做。这个控制器构建器需要将类型添加“堆叠”到所有中间件的Request对象中。
样品

class ControllerBuilder<RequestType> {
   addMiddleWare(middleWare): ControllerBuilder<RequestType & middlewareTypeAdditions> {
   // implementation
 }
}

字符串
为了提取中间件类型-我需要有它声明的someware。这就是为什么我引入了一个 * decored * 中间件。
下面是Decorate中间件的抽象:

abstract class DecoratedMiddleware<MiddlewareReqTypeAdditions> {
  ///
}


现在,在ControllerBuilder中,我们可以“提取”每个中间件的类型,并通过返回unin类型的新示例来“堆叠”它们:ReqeustType到目前为止与新中间件将添加的附加项相统一

class ControllerBuilder<RequestType> {
   addMiddleWare(middleWare: DecoratedMiddleware<MiddlewareReqTypeAdditions>): ControllerBuilder<RequestType & MiddlewareReqTypeAdditions> {
   // implementation
   return new ControllerBuilder<>
 }
}


下面是的示例中间件实现。我们只需要声明请求的附加属性,构建器将设置这些属性。流程函数必须返回这些 prop 的Promise,确保所有的设置都符合中间件类型的约定。

type AuthRequestAddtion = {
  role: string;
  id: number | string;
  hotelId: number;
};

class AuthMiddleware extends DecoratedMiddleware<AuthRequestAddtion> {
  protected process: MuddlewareFunc<AuthRequestAddtion> = (req, res) => {
    return Promise.resolve({
      id: 1,
      role: 'GUEST',
      hotelId: 3,
    });
  };
}


最后是一个示例用法:

ControllerBuilder.get(router(), '/with-weather')
  .addMiddleware(authMiddleware)
  .addMiddleware(multipartMiddleware)
  .addMiddleware(weatherMiddleware)
  .handle(async (req, res) => {
    //now we have types for all the middlewares
    const hotelId = req.hotelId;
    const files = req.files;
    const temp = req.weather.temperature;
    res.status(200).json({ hotelId, files, temp });
  });


构建器并不是100%完成的,我的意图是展示这种方法。我可能会修改它,以便可以使用一套中间件。
请注意,在调用handle之前,它的行为与生成器相同。因此,它是不可变的,可以链接,结果可以重用
大概是这样的:

const authUserWithWeather = ControllerBuilder.create()
  .addMiddleware(authMiddleware)
  .addMiddleware(weatherMiddleware);

authUserWithWeather.get("/").handle(() => {});
authUserWithWeather
  .addMiddleware(multipartMiddleware)
  .get("/something")
  .handle(() => {})


再次链接到演示:stakc-blitz modified

xzv2uavs

xzv2uavs2#

我在我的应用程序中使用了一个简单的解决方案,我只想对类型进行一次更改。我基本上在中间件函数中有一些逻辑,我知道如果请求对象通过中间件,它将保证某个属性存在于我的请求对象上,因此使用util中的附加属性创建具有请求类型的路由器。它当然不是通用的,但对于更简单的情况,它可以完成工作。

import { NextApiRequest, NextApiResponse } from 'next'
import { createRouter } from 'next-connect'
import { getAuth } from 'my-auth'

type NextApiRequestAuthed = NextApiRequest & {
  userId: string
}

export function getAuthRouter<ResponseData = any>() {
  const router = createRouter<NextApiRequestAuthed, NextApiResponse<ResponseData>>()
  router.use(async (req, res, next) => {
    const auth = getAuth(req)
    if (auth.userId == null) {
      return res.status(400)
    }
    req.userId = auth.userId
    await next()
  })
  return router
}

字符串
然后它可以简单地像这样使用:

type ResponseData = { data: string }
const router = getAuthRouter<ResponseData>()

router.get(async (req, res) => {
  const { userId } = req /* type of req is NextApiRequestAuthed */
  ...

相关问题