
簡單介紹了如何在Nancy中生成一份API文檔,并且探讨其在Nancy的内部實作原理。
前後端分離,或許是現如今最為流行開發方式,包括UWP、Android和IOS這樣的手機用戶端都是需要調用背景的API來進行資料的互動。
但是這樣對前端開發和APP開發就會面臨這樣一個問題:如何知道每個API做什麼?
可能,有人會在内部形成一份word文檔、pdf;有人會建立一個單獨的站點,然後将API的位址,參數等資訊列在上面;有人會借助第三方的工具來生成一份文檔等。
當然,這基本是取決于不同公司的規範。
說起API文檔,就想到前段時間做的微信小程式,由于那個不完善的接口文檔,進而導緻浪費了很大一部分時間去詢問接口相關的内容(用的是老的接口)。
為了處理這個問題,我認為,如果能在寫某個API的時候就順帶将這個API的相關資訊一并處理了是最好不過!
不過這并不是讓我們寫好一個接口後,再去打開word等工具去編輯一下這個API的資訊,這樣明顯需要花費更多的時間。
下面就針對這一問題,探讨一下在Nancy中的實作。
其實,想在Nancy中生成API文檔,是一件十分容易的事,因為作者thecodejunkie已經幫我們在Nancy内部提前做了一些處理
便于我們的後續擴充,這點還是很貼心的。
下面我們先來寫點東西,後面才能寫相應的API文檔。
基本的CURD,沒有太多的必要去解釋這些内容。當然這裡需要指出一點。
正常情況下,我們基本都是隻寫前面兩個參數的,後面兩個參數是可選的。由于我們後面需要用到每個路由的名字
是以我們需要用到這裡的第4個參數(目前路由的名字),也就意味着我們要在定義的時候寫多一點東西!
注: 1.x和2.x的寫法是有差別的!示例用的2.x的寫法,是以各位要注意這點!
以GET為例,方法定義大緻如下
API寫好了,下面我們先來簡單擷取一下這些api的相關資訊!
前面也提到,我們是要把這個api和api文檔放到同一個站點下面,免去編輯這一步驟!
世間萬物都是相輔相成的,我們不想單獨編輯,自然就要在代碼裡面多做一些處理!
新起一個Module名為<code>DocModule</code>,将api文檔的相關内容放到這個module中來處理。
沒錯,你沒看錯,就是這幾行代碼,就可以幫助我們去生成我們想要的api文檔!其實最主要的是IRouteCacheProvider這個接口。
它的具體實作,會在後面的小節講到,現在先着重于使用!
先調用這個接口的GetCache方法,以拿到緩存的路由資訊,這個路由資訊有必要來看一下它的定義,因為不看它的定義,我們根本就沒有辦法繼續下去!
後續的查找都是依賴于這些緩存資訊!
看了上面的定義,就可以清楚的知道要用SelectMany去拿到那個元組的内容。再取出元組的RouteDescription。
當然,這個時候我們取到的是所有的路由資訊,這些資訊都包含了什麼内容呢?看看RouteDescription的定義就很清晰了。
在查詢之後,我還過濾了那些名字為空的,不讓它們顯示出來。為什麼不顯示出來呢?理由也比較簡單,像DocModule,我們隻定義了一個路由
而且這個路由在嚴格意義上并不屬于我們api的内容,而且這個路由也是沒有定義名字的,是以顯示出來的意義也不大。
過濾之後,就得到了最終想要的資訊!簡單起見,這裡是先直接 傳回一個json對象,便于檢視有什麼内容,便于在逐漸完善後再把它結構化。
下面是最簡單實作後的大緻效果:
在圖中,可以看到GetProductList和GetProductByProductId這兩個api的基本資訊:請求的method,請求的路徑和路由片段。
但是這些資訊真的是太少了!連api描述都見不到,拿出來,肯定被人狠狠的罵一頓!!
下面我們要嘗試豐富一下我們的接口資訊!
要讓文檔充實,總是需要一個切入點,找到切入點,事情就好辦了。仔細觀察上面的效果圖會發現,裡面的metadata是空的。當然這個也就是豐富文檔内容的切入點了。
從前面的定義可以看到,這個metadata是一個RouteMetadata的執行個體
這裡對我們比較重要的是Raw這個屬性,因為這個是在傳回結果中的一部分,它是一個字典,鍵是類型,值是這個類型對應的執行個體。
先定義一個<code>CustomRouteMetadata</code>,用于傳回路由的Metadata資訊(可根據具體情況進行相應的定義)。這個<code>CustomRouteMetadata</code>就是上述字典Type。
定義好我們要顯示的東西後,自然要把這些東西用起來,才能展現它們的價值。
要用起來還涉及到一個MetadataModule,這個命名很像NancyModule,看上去都是一個Module。
先定義一個<code>ProductsMetadataModule</code>,讓它繼承<code>MetadataModule<RouteMetadata></code>,
具體實作如下:
這裡的寫法就和1.x裡寫NancyModule的内容是一樣的,應該也是比較熟悉的。就不再累贅了。其中的desc是一個委托<code>Func<RouteDescription, TMetadata></code>。
預設傳回的是一個RouteMetadata執行個體,而要建立一個這樣的執行個體還需要一個字典,是以大家能看到上面的代碼中定義了一個字典。
并且這個字典包含了我們自己定義的資訊,其中Group和Description是完全的自定義,其他的是從RouteDescription中拿。
當然,這裡已經開了一個口子,想怎麼定義都是可以的!
完成上面的代碼之後,再來看看我們顯示的結果
可以看到我們添加的metadata相關的内容已經出來了!可能這個時候,大家也都發現了,似乎内容有那麼點重複的意思!
因為這些重複,就會讓人感覺這裡比較臃腫,是以我們肯定不需要取出太多重複的東西,目前隻需要metadata下面的這些就可以了。
下面來對其進行簡化!
簡化分為兩步:
第一步簡化:DocModule的簡化。
其實,DocModule已經是相當的簡單了,但是還能在簡潔一點點。這裡用到了RetrieveMetadata這個擴充方法來處理。
前面的做法是拿到路由的資訊後,用了兩個Select來查詢,而且查詢出來的結果有那麼一點臃腫,
而借助擴充方法,可以隻取metadata裡面的内容,也就是前面自定義的内容,這才是我們真正意義上要用到的。
下面是具體實作的示例:
經過第一步簡化後,已經過濾了不少重複的資訊了,效果如下:
第二步簡化:Metadata的簡化
在傳回Metadata的時候,我們是傳回了一個預設的<code>RouteMetadata</code>對象,這個對象相比自定義的<code>CustomRouteMetadata</code>複雜了不少
而且從上面經過第一步簡化後的效果圖也可以發現,隻有value節點下面的内容才是api文檔需要的内容。
是以還要考慮用自定義的這個CustomRouteMetadata去代替原來的。
修改如下:
由于<code>MetadataModule<TMetadata></code> 中的TMetadata是自定義的<code>CustomRouteMetadata</code>,是以在傳回的時候直接建立一個簡單的執行個體即可
不需要像<code>RouteMetadata</code>那樣還要定義一個字典。
同時,還要把<code>DocModule</code>中RetrieveMetadata的TMetadata也要替換成CustomRouteMetadata
經過這兩步的簡化,現在得到的效果就是我們需要的結果了!
最後,當然要專業一點,不能讓人隻看json吧!怎麼都要添加一個html頁面,将這些資訊展示出來:
當然,現在看上去還是很醜,文檔内容也并不豐富,但是已經把最簡單的文檔做出來了,想要進一步豐富它就可以自由發揮了。
既然這樣簡單的代碼就能幫助我們去生成api文檔,很有必要去研究一下Nancy幫我們做了什麼事!
從最開始的IRouteCacheProvider入手,這個接口對應的預設實作DefaultRouteCacheProvider
裡面的GetCache方法是直接調用了定義的委托變量。最終是到了IRouteCache的實作類RouteCache,這個類算是一個重點觀察對象!
内容有點多,就隻貼出部分核心代碼了
它在構造函數裡去生成了路由的相關資訊。
具體的生成方法如下:周遊所有的NancyModule,找到每個Module的RouteDescription集合(一個Module可以包含多個路由)
然後找到每個RouteDescription的描述,路由片段和metadata的資訊。最後把這個Module路由資訊添加到目前的對象中!
前面提到RouteDescription的描述,路由片段和metadata的資訊都是通過額外的方式拿到的,這裡主要是拿metadata來做說明
畢竟在上面最後的一個例子中,用到的是metadata的内容。
先調用定義的私有方法GetRouteMetadata,這個方法裡面的内容是不是和前面的MetadataModule有點類似呢,字典和建立RouteMetadata的執行個體。
重點的是provider。這個provider來源來IRouteMetadataProvider,這個接口就兩個方法。
Nancy這個項目中還有一個抽象類是繼承了這個接口的。但是這個抽象類是沒有預設實作的。
注:前面的原理分析都是基于Nancy這個項目。
這個時候,另外一個項目Nancy.Metadata.Modules就起作用了。我們編寫的MetadataModule也是要添加這個的引用才能正常使用的。
從上面編寫的MetadataModule可以看出這個項目的起點應該是MetadataModule,而且有關metadata的核心也在這裡了。
到這裡,已經将GetCache的内内外外都簡單分析了一下。至于擴充方法RetrieveMetadata就不在細說了,隻是selectmany和select的一層封裝。
本文粗略講解了如何在Nancy中生成API文檔,以及簡單分析了其内部的處理。
下一篇将繼續介紹這一塊的内容,不過主角是Swagger。
如果您認為這篇文章還不錯或者有所收獲,可以點選右下角的【推薦】按鈕,因為你的支援是我繼續寫作,分享的最大動力!
作者:Catcher Wong ( 黃文清 )
來源:http://catcher1994.cnblogs.com/
聲明:
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。如果您發現部落格中出現了錯誤,或者有更好的建議、想法,請及時與我聯系!!如果想找我私下交流,可以私信或者加我微信。