【问题标题】:What is the best way to automatically validate requests using Typescript?使用 Typescript 自动验证请求的最佳方法是什么?
【发布时间】:2020-03-10 16:01:34
【问题描述】:

我想使用 Typescript 接口轻松验证后端请求。有没有办法让它发生?我想做的事的例子:

import { Request, Response } from 'express'

interface AuthenticateParams {
    email: string
    password: string
}

type AuthenticationRequest = Request & {body: AuthenticateParams}

const authenticate = async (req: AuthenticationRequest, res: Response) => {
    if (typeof req.body !== AuthenticateParams) res.status(400).send('Invalid body')

    // DO STUFF
    let stuff

    res.status(200).send(stuff)
}

export default authenticate

【问题讨论】:

标签: node.js typescript express


【解决方案1】:

typescript 中的接口纯粹是编译时构造。您正在尝试做的是动态检查正文的类型。

您可以使用架构验证器实现您想要的。

【讨论】:

  • 拥有集成 json 模式验证和打字稿定义的东西会非常有用。这样您就不必两次定义“类型”:防止更新时出现错误。
【解决方案2】:

没有办法做到这一点。接口仅在编译和检查代码时存在,但 TypeScript 没有运行时。

一旦你的 TypeScript 代码被编译,它就会变成普通的 JavaScript。而且 JavaScript 没有接口的概念,所以无法检查。

您基本上需要编写自己的函数来验证接口,例如,检查对象上是否存在特定字段,或者它是特定类的实例。

【讨论】:

    【解决方案3】:

    是的,我知道接口在运行时不存在。我创建了这个解决方案,它验证我的输入并在我需要时给我输入错误。我认为我的标题有点误导,所以我还将标题更改为“使用 Typescript 自动验证请求的最佳方法是什么”。

    这个想法是强迫我为我希望用来验证后端端点的每个接口编写一个简单的模式。此外,为了尽量减少人为错误的可能性,我的 linter 类型检查 validatorObject 很重要。

    validateParams.ts:

    const validateParams: (targetObject: any, validatorObject: any) => boolean = (targetObject, validatorObject) => {
        if (typeof targetObject !== typeof validatorObject) return false
        if (typeof targetObject === 'object') {
            let validObject = true
            if (Array.isArray(targetObject)) {
                for (let subObject of targetObject) {
                    validObject = validObject && validateParams(subObject, validatorObject[0])
                }
            } else {
                for (let key of Object.keys(validatorObject)) {
                    if (typeof targetObject[key] === 'object') validObject = validObject && validateParams(targetObject[key], validatorObject[key])
                    if (typeof targetObject[key] !== typeof validatorObject[key]) validObject = false
                }
            }
            return validObject
        }
        return true
    }
    
    export default validateParams
    

    认证.ts

    import { Request, Response } from 'express'
    import validateParams from "./validateParams"
    
    interface AuthenticateParams {
        email: string
        password: string
    }
    
    const validatorObject: AuthenticateParams = {
        email: 'string',
        password: 'string'
    }
    
    type AuthenticationRequest = Request & {body: AuthenticateParams}
    
    const authenticate = async (req: AuthenticationRequest, res: Response) => {
        if (!validateParams(req.body, validatorObject)) res.status(400).send('Invalid body')
    
        // DO STUFF
        let stuff
    
        res.status(200).send(stuff)
    }
    
    export default authenticate
    

    updateUser.ts

    import { Request, Response } from 'express'
    import validateParams from "./validateParams"
    
    interface UpdateUserParams {
        name: string
        products: {
            name: string
            price: number
        }[]
    }
    
    const validatorObject: UpdateUserParams = {
        name: 'string',
        products: [{name: 'string', number: 0}]
    }
    
    type AuthenticationRequest = Request & {body: UpdateUserParams}
    
    const updateUser = async (req: UpdateUserParams, res: Response) => {
        if (!validateParams(req.body, validatorObject)) res.status(400).send('Invalid body')
    
        // DO STUFF
        let stuff
    
        res.status(200).send(stuff)
    }
    
    export default updateUser
    

    这不是最漂亮的解决方案,但我喜欢它自动验证我的请求并且如果我忘记更新我的验证器对象也会给我错误。但是,是的,在运行时获得 Typescript 接口会很棒。

    【讨论】:

      【解决方案4】:

      这是我检查属性键的最佳帮手,同时与打字稿集成。有一个变化是可以递归扩展。

      function hasKeys<T, K extends string | number | symbol>(
          obj: T, 
          keys: K | K[]
      ): obj is T & { [P in K]: unknown } {
          return Array.isArray(keys) ? keys.every(k => k in obj) : keys in obj;
      }
      
      declare const obj: unknown;
      
      if(typeof obj === "object" && obj !== null) {
          if("prop" in obj) {
              // Property 'prop' does not exist on type 'object'.ts(2339)
              let x = obj.prop;
          }
      
          if(hasKeys(obj, "prop")) {
              let x = obj.prop;
          }
      
          if(hasKeys(obj, ["prop1", "prop2"])) {
              let x = obj.prop1;
              let y = obj.prop2;
          }
      }
      

      【讨论】:

        【解决方案5】:

        如果您还维护 openapi 文档,则可以使用 express-openapi-validator 验证请求。它也适用于 fastify 和 Koa

        【讨论】:

          猜你喜欢
          • 2019-08-06
          • 1970-01-01
          • 2023-03-15
          • 2018-04-26
          • 1970-01-01
          • 1970-01-01
          • 2015-09-06
          • 2012-07-10
          • 1970-01-01
          相关资源
          最近更新 更多