使用class-validator替換Joi包的方法

前言

對每個接口的傳入參數進行校驗,是一個Web后端項目的必備功能,有一個npm包叫Joi可以很優雅的完成這個工作,比如這樣子:

const schema = {userId: Joi.string()
};
const {error, value} = Joi.validate({ userId: 'a string' }, schema);
復制代碼

我們使用Typescript是希望得到明確的類型定義,減少出錯的可能性。在一個后端項目中,給每個接口定義它的傳入參數結構以及返回結果的結構,是一件很值得做的事情,因為這樣給后續的維護帶來極大的便利。比如這樣子:

export type IFooParam = {userId: string
}export type IFooResponse = {name: string
}async foo (param: IFooParam): Promise<IFooResponse> {// Your business codereturn {name: 'bar'}
}
復制代碼

現在問題就來了,如果傳入參數希望加多一個字段,我們必須得修改2個地方,一個是Joi的校驗,一個是IFooParam類型的定義。有沒有好的辦法解決這個問題呢?

Class-validaotr

有一個npm包叫class-validator, 是采用注解的方式進行校驗,底層使用的是老牌的校驗包validator.js。
這次試用,發現通過一些小包裝,居然做到像Joi一樣優雅的寫法,而且更好用!

定義傳入/返回結構

import {Length, Min, Max} from 'class-validator'export class IRegister {@Length(11)phone: string@Length(2, 10)name: string@Min(18)@Max(50)age: number
}class Button {text: string
}export class ORegister {/*** user's id*/userId: stringbuttons: Button[]
}
復制代碼

這里定義了2個類,IRegister為傳入參數,通過class-validator規定的注解方式做校驗,ORegister為返回結果。

class-validator官方提供的方式還不能直接對一個請求的body進行校驗,它要求必須要是IRegister類的一個對象,所以需要做一些處理。

使用class-transformer做轉化

跟class-validator的作者也開源了另外一個包,叫class-transformer, 可以將一個json轉成指定的類的對象,官方的例子是這樣的:

import {plainToClass} from "class-transformer";let users = plainToClass(User, userJson); // to convert user plain object a single user. also supports arrays
復制代碼

利用這一點,我們寫一個小工具:

import * as classTransformer from 'class-transformer'
import {validate} from 'class-validator'
import * as lodash from 'lodash'export class ValidateUtil {private static instance: ValidateUtilprivate constructor () {}static getInstance () {return this.instance || (this.instance = new ValidateUtil())}async validate (Clazz, data): Promise<any> {const obj = classTransformer.plainToClass(Clazz, data)const errors = await validate(obj)if (errors.length > 0) {console.info(errors)throw new Error(lodash.values(errors[0].constraints)[0])}return obj}
}
復制代碼

這個小工具提供了一個validate方法,第一個參數是一個類定義,第二個是一個json,它先利用class-transformer將json轉成指定類的對象,然后使用class-validator做校驗,如果校驗錯誤將拋出錯誤,否則返回轉化后的對象。

在Controller中使用

有了上面的工具,就可以方便地在代碼中對傳入參數做校驗了,比如這樣:

  static async register(ctx) {const iRegister = await ValidateUtil.getInstance().validate(IRegister, ctx.request.body)const oRegister = await UserService.register(iRegister)ctx.body = oRegister}
復制代碼

新問題

到了這里,完美地使用class-validator替換掉了Joi。

但是還有一個問題沒解決,也是之前一直遺留的問題。

我們使用apidoc編寫接口文檔,當新增或修改一個接口時,是通過編寫一段注釋,讓apidoc自動生成html文檔,將文檔地址發給前端,可以減少雙方的頻繁溝通,而且對前端的體驗也是非常好的。比如寫這樣一段注釋:

  /*** @api {post} /user/registerOld registerOld* @apiGroup user* @apiName registerOld* @apiParam {String} name user's name* @apiParam {Number} age user's age* @apiSuccess {String} userId user's id */router.post('/user/registerOld', UserController.register)
復制代碼

apidoc會幫我們生成這樣的文檔:

問題比較明顯,當我們要新增一個參數時,需要修改一次類的定義,同時還要修改一次apidoc的注釋,很煩,由于很煩,文檔會慢慢變得沒人維護,新同事就會吐槽沒有文檔或者文檔太舊了。

理想的情況是代碼即文檔,只需要修改類的定義,apidoc文檔自動更新。

探索apidoc根據class-validator的定義生成

從同事的分享中得知一個廢棄的npm包,叫apidoc-plugin-ts, 可以實現根據ts的interface定義來生成apidoc的。官方的例子:

filename: ./employers.tsexport interface Employer {/*** Employer job title*/jobTitle: string;/*** Employer personal details*/personalDetails: {name: string;age: number;}
}@apiInterface (./employers.ts) {Person}
復制代碼

會轉化成:

 @apiSuccess {String} jobTitle Job title@apiSuccess {Object} personalDetails Empoyer personal details@apiSuccess {String} personalDetails.name@apiSuccess {Number} personalDetails.age
復制代碼

雖然不知道為什么作者要廢棄它,但是它的思想很好,源碼也很有幫助。

給我的啟發是,參考這個npm包,寫一個針對class定義來生成apidoc的插件就行了。

造輪子: apidoc-plugin-class-validator

輪子的制造細節不適合在這里陳述,基本上參考apidoc-plugin-ts,目前已經發布在npm上了,apidoc-plugin-class-validator

使用apidoc-plugin-class-validator

以上面的注冊接口為例,使用方法:

  /*** @api {post} /user/register register* @apiGroup user* @apiName register* @apiParamClass (src/user/io/Register.ts) {IRegister}* @apiSuccessClass (src/user/io/Register.ts) {ORegister}*/router.post('/user/register', UserController.register)
復制代碼

就會生成文檔:

后續新增字段,只需修改IRegister類的定義就行,真正做到了修改一處,處處生效,代碼即文檔的效果。

本文的demo代碼在這里,這是一個簡單的web后端項目,看代碼更容易理解。

轉載于:https://juejin.im/post/5c9b3b53f265da612e6d708c

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/536616.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/536616.shtml
英文地址,請注明出處:http://en.pswp.cn/news/536616.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

linux服務器下降,linux - 遠程升級Ubuntu:如何最大程度地降低丟失服務器的風險? - Ubuntu問答...

問題描述背景&#xff1a;由于raid控制器的不兼容性問題&#xff0c;我被迫將服務器從Ubuntu 8.04 LTS遠程升級到10.04 LTS。與服務器的Internet連接比較穩定&#xff0c;很少掉線。盡管如此&#xff0c;我還是擔心在升級時會丟失通過SSH的連接&#xff0c;從而使服務器處于無法…

Linux中英文命令對應

本文我們把Linux的中英文命令做了對應翻譯&#xff0c;給需要的朋友參考一下。很多朋友在論壇上找Linux英文命令&#xff0c;我們給大家整理了比較全的Linux英文命令&#xff0c;并且附上了對應的中文意思。 su&#xff1a;Swith user 切換用戶&#xff0c;切換到root用戶 cat:…

linux實驗四文件安全,西北農林科技大學Linux實驗四 用戶和文件安全

一、 實驗目的實驗四 用戶和文件安全1. 理解用戶、組的概念2. 理解/etc/passwd、/etc/group、/etc/shadow文件 3. 練習useradd、groupadd、gpasswd、groups命令二、 實驗內容 1. 添加用戶 2. 添加組3. 添加用戶到工作組 4. 改變目錄原始組 5. 建立多個用戶共享的目錄6. 理解文件…

Unable to resolve dependency問題解決

Unable to resolve dependency 是一個讓我頭疼的問題 之前總是陰差陽錯調試好 但是也沒有總結出來方法 但是今天找到了 方法來源 https://jingyan.baidu.com/article/19192ad8c489dfe53e5707ee.html 原因就是用戶的gradle.properties 設置了代理&#xff0c;將文件內的代理注釋…

linux 服務器進程,如何查看Linux服務器的進程

Linux服務器正常啟動后&#xff0c;提供服務時會調用程序&#xff0c;占用進程。這時候如何查看系統中有哪些進程在被調用呢&#xff1f;我們可以通過以下命令來查看。1.psps命令是最基本同時也是非常強大的進程查看命令。使用該命令可以確定有哪些進程正在運行和它所運行的狀態…

計數排序與桶排序python實現

計數排序與桶排序python實現 計數排序 計數排序原理&#xff1a; 找到給定序列的最小值與最大值 創建一個長度為最大值-最小值1的數組&#xff0c;初始化都為0 然后遍歷原序列&#xff0c;并為數組中索引為當前值&#xff0d;最小值的值&#xff0b;&#xff11; 此時數組中…

perl腳本執行linux命令行,Perl調用shell命令方法小結

一、systemperl也可以用system調用shell的命令,它和awk的system一樣,返回值也是它調用的命令的退出狀態.代碼如下:[rootAX3sp2 ~]# cat aa.pl#! /usr/bin/perl -w$file "wt.pl";system("ls -l wt.pl");$result system "ls -l $file";print &qu…

JVM快速調優手冊02:常見的垃圾收集器

2019獨角獸企業重金招聘Python工程師標準>>> 如果說收集算法是內存回收的方法論&#xff0c;那么垃圾收集器就是內存回收的具體實現。 Java虛擬機規范中對垃圾收集器應該如何實現并沒有任何規定&#xff0c;因此不同的廠商、不同版本的虛擬機所提供的垃圾收集器都可…

linux運維平臺工具,Linux運維自動化工具 Kickstart

簡介&#xff1a;批量安裝操作系統工具之 Kickstart &#xff0c;RedHat 早前推出的產品( 不多說了&#xff0c;現在都玩 Cobbler 啦&#xff0c;見 http://www.linuxidc.com/Linux/2016-04/129977.htm )。測試環境&#xff1a;CentOS 6.6 x86_64 minimal一、安裝軟件包shell &…

PostgreSQL 并行查詢概述

2019獨角獸企業重金招聘Python工程師標準>>> PostgreSQL從9.6版本開始加入并行查詢&#xff0c;并在PostgreSQL10和PostgreSQL11分別做了大量加強工作。下面從&#xff1a; 何時啟用并行查詢功能并行查詢是如何工作的worker進程數量越多&#xff0c;查詢性能越高嗎三…

linux下得到date命令,linux下date命令獲得今天日期的用法

1。獲取今天日期的各類用法&#xff1a;oracle[roottest ~]# date %Y_%m_%d2016_05_22[roottest ~]# date %Y_%m_%d2016_05_22ide[roottest ~]# date "%Y_%m_%d"2016_05_22[roottest ~]# date %Y_%m_%d2016_05_22[roottest ~]# date "%Y_%m_%d"2016_05_22i…

Quarkus:一個Kubernetes原生Java框架

Red Hat發布了Quarkus&#xff0c;這是一個為GraalVM和OpenJDK HotSpot量身定制的Kubernetes原生Java框架。Quarkus的目標是使Java成為Kubernetes和無服務器環境中的領先平臺&#xff0c;為開發人員提供統一的反應式和命令式編程模型。 Quarkus利用Java開發人員使用的一系列庫&…

分區安裝linux,怎樣安裝Linux?

我的機子上裝了win2000&#xff0c;想裝個Linux可是在安裝時&#xff0c;竟然D 、E盤都不見了&#xff0c;win2000也進不去了我只得重裝2000&#xff0c;現在我都不敢裝Linux了請高手指點&#xff01;|你最好用PQMAGIC先分區&#xff0c;大約2。5G空間就夠了&#xff0c;可以參…

linux scp傳輸文件命令

scp -r /opt/test root192.168.2.105:/opt 轉載于:https://www.cnblogs.com/LynnChen/p/10620576.html

pg10 10.3 1 linux64,Install Postgresql 10 In Ubutnu 16.04 LTS

PostgreSQL數據庫是一個高性能的全功能的開源關系型數據庫&#xff0c;這里講解一下如何在Ubuntu 16.04 LTS 下安裝 PostgreSQL 10。添加軟件源wget -q -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -sudo sh -c echo "deb http://apt.po…

nginx能訪問html靜態文件但無法訪問php文件

nginx.conf中紅框部分修改成你的實際網站根目錄轉載于:https://www.cnblogs.com/IT-Crowd/p/10626549.html

linux虛擬光驅掛載方法,Linux操作系統下虛擬光驅(iso)的掛載

1、掛載iso文件一般查看iso文件內容&#xff0c;只需要&#xff1a;#mount -t iso9660 -o loop xxx.iso /mnt/cdrom就可以在/mnt/cdrom下看到xxx.iso的內容。2、復制光盤為iso鏡像#dd if/dev/hdb ofxxx.iso或者#cp /dev/cdrom xxx.iso3、虛擬iso為設備#rm -rf /dev/cdrom //刪除…

[深度概念]·K-Fold 交叉驗證 (Cross-Validation)的理解與應用

個人主頁--> xiaosongshine.github.io/ 1.K-Fold 交叉驗證概念在機器學習建模過程中&#xff0c;通行的做法通常是將數據分為訓練集和測試集。測試集是與訓練獨立的數據&#xff0c;完全不參與訓練&#xff0c;用于最終模型的評估。在訓練過程中&#xff0c;經常會出現過擬合…

linux mariadb 升級,linux mariadb

linux mariadb轉載 一 安裝下載mariaDB MariaDB-5.5.29-rhel5-x86_64-common.rpm 和MariaDB-5.5.29-rhel5-x86_64-server.rpm 包,MariaDB-5.5.29-rhel5-x86_64-client.rpm2.然后再http.//yum。mariadb。org/ 找到 RPM-GPG-KEY-MariaDB 這個PGP文件&#xff0c;把文件放入到/etc…

Linux Note

日期&#xff1a;2019/3/31 內容&#xff1a;Linux學習筆記 一、Linux命令 ls -l 操作效果 第一列&#xff1a;文件權限 一共10位。 01(r)2(w)3(x)4(r)5(w)6(x)7(r)8(w)9(x)文件類型文件所有者權限 usr權限&#xff0c;u權限文件所有者所屬組成員的權限 group權限&#xff0c;g…