如何使用TypeScript将输入的JSON对象转换为Node.JS中的模型类?

时间:2018-08-23 23:10:56

标签: node.js typescript express

我正在使用TypeScript和express框架编写Node.js服务器。 这是我的控制器和路由的样子:

  export class AuthController {

        public async signUpNewUser(request: Request, response: Response) {
        ...
    }
}

如何像在ASP.NET中那样接收模型类而不是请求类型? 像这样:

public async signUpNewUser(input: SignUpModel, response: Response) {

这是个好主意吗?我不确定这是Node.JS中的常用方法 我只想确保每次都获得相同的模型,并编写与此模型相关的代码,而不是在动态JSON对象上。

我的建议是在路线开始时转换为强类型模型,但是我不确定这是一个好方法。

有人对这种情况有解决方案吗?

2 个答案:

答案 0 :(得分:1)

所以您似乎有几个不同的问题。核心问题是“如何将JSON对象转换为特定类型”,但是随后您还会询问这是否是一个好主意,以及这是否是常见的做法。

第一个问题的答案非常简单,您可以像这样在您的路线(或任何地方)中投射它:

router.get('/whatever', (req, res) => {
   const signup: SignupModel = JSON.parse(req.model) as SignupModel;

   // Do whatever you want with the signup model
});

现在,您的其他问题更基于观点。如果说实话,我会说“不要使用Typescript”。 :)开个玩笑,我不知道该如何回答您的基于意见的问题(也不适合该网站)

答案 1 :(得分:1)

  

如何接收模型类而不是像ASP.NET中那样的请求类型

在我的项目中(以及在工作中),这一直让我痛苦不已。最终,我们决定使用自己的默认错误处理和auth-header检查来构建自定义路由器。这种模式的诀窍是保持轻量级,因为该 is 仍然可以表达,而中间件是应该去的地方-此包装器只是为我们提供了一种将表达请求转换为基于形状的适当类型的方法在我们实际使用的中间件上。

这是一个简化的示例,其思想是您可以通过传递接口(或内联类型的形状)来指定req&res的形状,并让打字稿强制执行返回形状。

包装类示例:

import * as express from 'express';

export type ExpressMethods = "get" | "post" | "put" | "delete" | "patch";

export type JsonRouteInput<RequestBody, RouteParams, QueryParams> = {
  body: RequestBody;
  params: RouteParams;
  query: QueryParams;
};

export type JsonRouteHandler<
  RequestBody,
  RouteParams,
  QueryParams,
  ResponseBody
> = (
  request: JsonRouteInput<RequestBody, RouteParams, QueryParams>
) => Promise<ResponseBody> | ResponseBody;

export class JsonRouter {
  router = express.Router();
  private addHandler<M extends ExpressMethods>(
    method: M,
    ...middleware: express.RequestHandler[]
  ) {
    this.router.use(...middleware);
  }

  get route(): {
    [K in ExpressMethods]: <
      RequestBody,
      ResponseBody,
      RouteParams = never,
      QueryParams = never
    >(
      path: string,
      handler: JsonRouteHandler<
        RequestBody,
        RouteParams,
        QueryParams,
        ResponseBody
      >
    ) => JsonRouter
  } {
    const addables = {} as any;
    (["get", "post", "put", "delete", "patch"] as ExpressMethods[]).forEach(
      <RequestBody, ResponseBody, RouteParams = never, QueryParams = never>(
        method
      ) => {
        addables[method] = (
          path: string,
          handler: JsonRouteHandler<
            RequestBody,
            RouteParams,
            QueryParams,
            ResponseBody
          >
        ) => {
          this.router[method](path, async (req, res) => {
            try {
              const responseBody: ResponseBody = await handler({
                body: req.body,
                params: req.params,
                query: req.query
              });
              res.json(responseBody);
            } catch (err) {
              // do your standard error handling or whatever
              res.status(500).end("ow");
            }
          });
          return this;
        };
      }
    );
    return addables;
  }
}

然后使用它

const jsonRouter = new JsonRouter().route.get<{ request: number }, { response: number }>(
  "/hello-world",
  req => {
    return { response: req.body.request + 1 }; // type-checked result
  }
);

这绝对可以再进一步-我有一些原型,可以让我们半流畅地构建请求/响应主体的形状。长期采用这种策略的目标是,我们可以为前端生成一个打字稿休息客户端,生成与我们用于注释的类型匹配的输入验证,并强制响应是正确的类型-example router using this strategy to build the type dynamically < / p>

编辑:将此示例插入快递服务器

const app = express();

// custom middleware goes here

app.use('/', jsonRouter.router);

app.listen(8000)