「本文首發於個人博客,轉載請註明出處html
」前端
網上時不時就能看到一些求助帖,大意是先後端集成所產生的一些爭執,其實集成的時候若是能有一些」規範「,這件事情能夠很簡單。ios
本文跟技術棧強相關,可是理論上從裏面抽離出來的方法論能夠實踐在任意的技術棧上,只須要投入一點點時間和精力寫一個小工具就行了,下面是本文所用到的一些技術棧:git
其中最後一項就是上面提到的須要本身去實現的小工具,這裏我是把組裏以前給redux用的工具改了一版,先是從 swagger2.0 升級到 openAPI 標準,而後改成生成 SWR 的代碼而不是redux的,具體工具怎麼使用能夠看個人 github,裏面有詳細的 readme 和 example。這個工具雖然簡單,倒是先後端集成不可或缺的重要組成部分,稍後咱們會講到。程序員
而後 SWR 是一個很酷的用於獲取遠端數據的一個基於 React hooks 的請求庫。它實現了 HTTP 規範中的 stale-while-revalidate
,即其會先使用 catch 中已存在的 data 先渲染頁面,而後發送新的請求去驗證 catch 中的 data 是否爲最新,若是已是最新則什麼都不作,若是不是最新則更新本地的 catch 而後使用最新的 catch 從新渲染頁面。github
這樣作的好處是能夠極大地提高用戶體驗,用戶在重複瀏覽同一頁面時,若是頁面數據更新不頻繁則沒有任何等待時間。在新項目上使用幾個月後,我欣喜地發現 SWR 登上了 ThoughtWorks 最新一期的技術雷達,和 Recoil、Svelte 一塊兒暫時位於評估象限。npm
SWR in tech radarjson
不過技術雷達也一針見血地指出了 SWR 的缺陷:redux
「咱們的開發者在使用 SWR 時得到了很好的開發體驗,而且由於數據老是顯示在屏幕上,從而顯著提高用戶體驗。然而,咱們提醒團隊,只有當應用程序返回過期數據是合適的時候,才能使用 SWR 緩存策略。要注意,HTTP 一般要求緩存要用最新的響應返回給請求,只有在須要_很是慎重的場景_下,纔會容許返回過期的響應數據。axios
」
也就是說,若是你的壞境對數據更新的要求極高,須要實時拿到最新的數據的話,不適合使用 SWR。
TypeScript 如今幾乎成爲了一門前端必上的技術棧,相比 JavaScript,其提供的類型系統可以保證程序員們常犯的」低級錯誤「在寫代碼時就暴露出來。
但也是因爲其類型系統,咱們在集成後端 API 時須要寫一堆麻煩的接口類型,好比一個 request 的參數,這個 response 的數據類型等等。
而這些接口類型實際上是後端定義的,咱們實際上是在依賴後端寫的接口來寫類型。這就很尷尬了,後端改了接口,前端也得跟着改類型,這多麻煩,後面咱們會一塊兒解決這個問題。
要解決一個問題,那麼咱們首先應該作的是想清楚爲何會出現這樣的問題。
首先咱們來回憶一下常規的開發過程:拿到需求,先後端討論出接口的各類參數,開始寫代碼,這中間可能後端(前端)發現有問題,而後改接口,而後差很少寫好的接口得從新改,改類型,改參數。
這是常規的,不常規的呢?後端本身定好接口的參數,而後告訴你他要啥給你啥,而後你按照他給的寫,寫好發現不能用,去找他,他說接口改了,你從新改下。那還能咋說,只能網上對線了。
說白了就是,先後端討論好的東西可能會變(甚至都沒有通過討論,由單方面直接決定好了),變了以後因爲各類各樣的緣由沒能及時同步信息,即便及時同步了,改接口代碼也是一件煩人的事情。
咋辦?
首先,咱們須要搞清楚什麼是契約測試?
契約測試,又叫」消費者驅動的契約測試「(Consumer-Driven Contracts,簡稱CDC)。其中有兩個角色,一個消費者,一個生產者。由消費者提供一份本身的」需求清單「(契約,約定好request和response),而後生產者根據「清單」進行相應實現。以後雙方依賴於這份契約進行測試和實現。
其實契約測試將依賴雙方作了一個相似於解耦的操做,從消費者依賴於生產者變成雙方依賴於消費者提供的契約。咱們是否是能夠運用這個思想呢?
其實大多數項目裏已經有一份契約了,沒錯,就是 swagger。只不過這份契約是生產者提供的,並且由生產者決定上面有啥,消費者無法決定。
可是其實咱們能夠將這份契約作一個轉換。swagger 上一般會給出 API 的詳細信息,包括 request 的參數和 response 長什麼樣子。並且其實 swagger 只是一份 json 文件,咱們所看到的 swagger-ui 是後端的 lib 自動生成的。那麼咱們是否是能夠拿到這份 json 文件。解析後直接生成前端須要的 request 和類型呢?
這樣帶來了幾個好處:
說了這麼多都是理論,誰知道效果呢?不要緊,咱們直接上代碼,下面全部的代碼均可以在連接裏面找到。
首先看一下這個example的目錄:
「. |____swagger | |____openAPI.json |____types.ts |____request | |____api.ts | |____useRequest.ts | |____client.ts |____page.tsx
」
其中 swagger 文件夾下是我從網上生成的 openAPI 規範的 swagger 文檔。
request 文件夾下有三個文件:
這東西怎麼用呢?
首先固然是安裝這個包 npm i @openapi-integration/swr-request-generator -D
而後在項目的根目錄添加一個配置文件,裏面能夠配置生成文件的輸出目錄,文件名,須要提早引入的方法,從哪裏拿到 swagger 文件等(具體能夠看readme)
而後跑一下 npm run ts-codegen
,就會在你配置的相應生成對應的 API 文件。
好比下面這個方法就是生成的:
``import { ISWRConfig, useRequest } from "./useRequest";
import { IResponseError } from "../types";
import { client } from "./client";
export const useDownloadUsingGetRequest = (
{
id,
}: {
id: string;
},
SWRConfig?: ISWRConfig<IResource, IResponseError>,
) =>
useRequest<IResource, IResponseError>(
{
url: /${id}
,
method: "get",
},
SWRConfig,
);
export interface IResource {
description?: string;
file?: IFile;
filename?: string;
inputStream?: IInputStream;
open?: boolean;
readable?: boolean;
uri?: IUri;
url?: IUrl;
}
``
而你只須要在調用的時候直接:
`const = { data, error } = useDownloadUsingGetRequest({ id: "id"})
`
假如後端改了代碼,這個接口不要 id 了,要 name,你只須要從新跑一次npm run ts-codegen
,而後這個方法就會更新,TypeScript 就會報錯,告訴你這裏要的是 name 不是 id,若是 response 的結構也改了,那麼所生成的文件裏面的 response 的類型也會跟着變, TypeScript 依然會提醒你 response 結構的改變。
這樣一來接口不管怎麼變其實前端都不在乎,頂多就是跑一遍命令,從新穿個參數就行了,大大提高開發效率,下降內耗。