在Javascript中使用DTO的示例詳解
什么是DTO
DTO 英文是 data transfer object 的縮寫,意思為“數(shù)據(jù)傳輸對(duì)象”,它是指定義了一個(gè)包含一組值或字段的容器,而不是解釋如何在層之間傳遞數(shù)據(jù)的方法。有些人混淆了定義數(shù)據(jù)庫(kù)模型(Modal)和DTO,記住這句話:
DTO 是用來(lái)操作和數(shù)據(jù)傳輸?shù)?,而模型則是用于數(shù)據(jù)持久性的。
什么時(shí)候使用DTO?
很多開發(fā)人員在用 typescript/nodejs 開發(fā)復(fù)雜的應(yīng)用程序時(shí),都會(huì)使用 DTO 來(lái)表示他們的數(shù)據(jù)以及數(shù)據(jù)是如何傳輸?shù)綉?yīng)用程序的各個(gè)層的。這實(shí)際上是正確的,也是必需的。
但我今天來(lái)告訴你,這也是javascript/nodejs 開發(fā)中所必需的,這樣做可以防止你的代碼變得糟糕??!
為什么要在 Javascript 中使用 DTO?
想象一下,你用 javascript 開發(fā)動(dòng)態(tài)頁(yè)面,并使用 nodejs 開發(fā)rest API,你開始創(chuàng)建模型,做數(shù)據(jù)驗(yàn)證,例如使用“express-validator”,并定義了你的路由、中間件,一起工作正常。
隨著需求的變化和代碼的頻繁更新,會(huì)有多個(gè)服務(wù)和多個(gè) API 以不同的方式使用同一個(gè)模型,并且在每個(gè)服務(wù)中復(fù)制一些字段,以將它們從控制器(Controller)層傳遞到服務(wù)(Service)層,然后傳遞到負(fù)責(zé)將數(shù)據(jù)持久化到數(shù)據(jù)庫(kù)中的層。當(dāng)一段時(shí)間后再看代碼,如果已經(jīng)看不明白什么數(shù)據(jù)應(yīng)該傳遞給服務(wù)層,什么數(shù)據(jù)應(yīng)該從這個(gè)服務(wù)返回,那么你就需要 DTO 了。
再想象一下,如果你在沒有嚴(yán)格的 schema 的情況下,連接到一個(gè)作為持久性數(shù)據(jù)庫(kù)或文檔數(shù)據(jù)庫(kù)的firebase,并且你將 json 數(shù)據(jù)作為端點(diǎn),使用“express-validator”進(jìn)行一些驗(yàn)證,并將這些數(shù)據(jù)傳遞到服務(wù)層,然后這個(gè)服務(wù)層將這些數(shù)據(jù)傳輸?shù)匠志眯詫?,你需要的字段如下所示?/p>
{ username: String, email: String, password: String }
你如何保證 API 消費(fèi)者可以發(fā)送更多的字段而不是定義的字段?例如,API 的消費(fèi)者可以發(fā)送以下數(shù)據(jù):
{ "username": "test", "email": "test@gmail.com", "password": "specificPass", "birthDate": "2022-05-09T20:12:13.318Z" }
你看,我可以發(fā)送驗(yàn)證中未定義的字段birthDate
,這將違反服務(wù)的約定,這些數(shù)據(jù)也會(huì)被傳遞到持久層,并將保存在數(shù)據(jù)庫(kù)中。
同樣,假設(shè)有一個(gè)使用相同服務(wù)層的 API 和 web socket 連接,要如何定義兩者的驗(yàn)證?你最終可能會(huì)在兩者中重復(fù)定義公開的數(shù)據(jù)!
在所有這些情況下,您都需要DTO。其背后的想法很簡(jiǎn)單,它使你能夠描述如何在層中接收數(shù)據(jù)和公開數(shù)據(jù)。
實(shí)施和示例
最初,我們將 express js 路由定義如下:
router.post("/user/register", validations, registerController);
我們將使用express驗(yàn)證器進(jìn)行如下驗(yàn)證:
const validations = [ body("username").exists().isString().notEmpty(), body("email").exists().isEmail(), body("password").exists().isString().notEmpty(), ]
然后,控制器/處理程序如下所示:
const registerController = (req, res) => { const result = await userService.registerUser(req.body); return res.status(200).json(result); }
簡(jiǎn)單服務(wù)層如下所示:
const registerUser = (userData) => { userPersistenceLayer.add(userData); }
現(xiàn)在,讓我們定義我們的基本DTO,但在此之前,讓我確保兩個(gè)事實(shí):
- DTO用于數(shù)據(jù)傳輸,數(shù)據(jù)庫(kù)模型用于數(shù)據(jù)持久性。
- 將DTO視為一種約定,您可以使用此約定規(guī)范與其他人進(jìn)行處理。約定規(guī)范是其中定義的字段
class RegisterUserDTO{ username; email; password; ? constructor(data) { this.username = data.username; this.email = data.email; this.password = data.password; } }
然后我們可以回到服務(wù)層并使用我們定義的DTO:
const registerUser = (userData) => { userPersistenceLayer.add(new RegisterUserDTO(userData)); }
正如您在這個(gè)模式中看到的那樣,我們正在控制傳遞數(shù)據(jù)的方式,并確保哪些字段被傳遞到其他層,我們還可以在這個(gè)DTO中設(shè)置一些getter和setter,以根據(jù)需要序列化/轉(zhuǎn)換一些數(shù)據(jù)。
希望你能清楚、順利地了解DTO模式。
到此這篇關(guān)于淺聊為什么在Javascript中使用 DTO的文章就介紹到這了,更多相關(guān)在Javascript中使用 DTO內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript中Object基礎(chǔ)內(nèi)部方法圖
本篇文章通過一張?jiān)敿?xì)的JavaScript中Object基礎(chǔ)內(nèi)部方法圖介紹了其基本用法,需要的朋友參考下。2018-02-02js+canvas實(shí)現(xiàn)飛機(jī)大戰(zhàn)
這篇文章主要為大家詳細(xì)介紹了js?canvas實(shí)現(xiàn)飛機(jī)大戰(zhàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05微信小程序掃描普通二維碼跳轉(zhuǎn)到小程序指定頁(yè)面操作方法
這篇文章主要給大家介紹了關(guān)于微信小程序掃描普通二維碼跳轉(zhuǎn)到小程序指定頁(yè)面操作的相關(guān)資料,為了分享方便,或者制作宣傳海報(bào)之類的,經(jīng)常需要用到微信小程序指定頁(yè)面的二維碼,讓用戶掃碼直達(dá)頁(yè)面,需要的朋友可以參考下2023-08-08多個(gè)js毫秒倒計(jì)時(shí)同時(shí)進(jìn)行效果
這篇文章主要以實(shí)例的方式講解多個(gè)js毫秒倒計(jì)時(shí)同時(shí)進(jìn)行效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-01-01詳解js中Number()、parseInt()和parseFloat()的區(qū)別
本文主要對(duì)js中Number()、parseInt()和parseFloat()的區(qū)別進(jìn)行詳細(xì)介紹,具有很好的參考價(jià)值,需要的朋友一起來(lái)看下吧2016-12-12js實(shí)現(xiàn)列表向上無(wú)限滾動(dòng)
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)列表向上無(wú)限滾動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-01-01