est的作者認為計算機發展到現在,最大的成就不是企業應用,而是web,是漫漫無邊的互聯網web世界。Web能有這么大的成就,它值得我們研究。所以Rest的作者仔細研究了Web,按照Web的世界一些關鍵特性,提出了我們在實現企業應用的時候應該遵循的一種風格,就是Restful。
Rest風格的API可以給我們很多好處,比如:簡潔,統一,性能,可擴展性等等??上У氖牵趯崿FRest的時候,總有一些Rest的關鍵特性沒有實現,比如,無狀態性,這在我做過的兩個項目和我知道的另外一個項目都存在。事實上要實現無狀態性在java里不是那么容易,因為那意味著要把servlet的session拋棄了。除此之外,Rest的一些其他特性在各個項目中實現的也是各有不同。
接下來,我會列出一些我認為的,要實現Rest風格API的關鍵步驟:
1. 所有東西都是資源(Resource)
所有要給API操作的對象都只能是資源。不管實際上存在的,還是抽象上的。所有資源都會有一個不變的標識(ID),對資源的任何API操作都不應該改變資源的標識。資源和其他資源會有關系,資源與資源的關系通過資源的標識來引用。對資源的操作都應該是完整的,比如獲取資源拿到的應該是一個完整的資源對象(根據企業引用特點有些例外,后面會提到)。
事實上,上面的這些完完全全是按照互聯網的特性提出來的。互聯網中,一個URL就是一個資源;資源的內容就是HTML頁面;不管怎么改HTML內容,URL都不會改變;資源之間通過HTML里的連接聯系起來;每次獲取的時候,獲取到的都是完整的HTML內容。
假設有一個博客系統,那么其中的資源可以包括:博主,每個博主都是一個資源;博客,每篇博客都是一個資源,博客和博主之間有聯系,通過ID聯系起來;每篇博客都會有回復,回復也算是資源,但是它是隸屬于博客的,可以認為回復是博客的子資源(你也可以認為博客是博主的子資源,怎么抽象取決于具體的應用,這里不討論)。
這步通常不難實現,因為這和ORM中的對象概念是類似的,實現上,如果用了Hibernate之類的框架,改動也應該很小。
2. 規范對資源的操作,最好只包括CRUD
CRUD指創建(Create),讀?。≧ead), 更新(Update),刪除(Delete)
通常對資源的操作只包含CRUD是不可能的,CRUD里甚至連查找的操作的都沒有。但這不妨礙我們對Rest的理解,Rest提出的要求是,對資源的操作都應該是統一的,不管是操作哪種類型的資源,API都應該是一致的。這樣當調用API的客戶端知道某種資源的時候,它不需要去學習對這個資源該怎么操作,因為對所有資源的操作都是一致的,它們都應該支持CRUD操作,以及一些其他操作,比如list(用來查找,或者列出所有資源), merge(部分更新資源,這應該是唯一的不操作資源所有內容的API)。
這和Web也是一樣的,HTTP里只有GET,PUT,POST,HEAD等等幾個統一的請求(參考:http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html)。
要實現簡單的幾個操作不難,難在這幾個簡單操作沒法支撐整個系統的需求。但是想想吧,互聯網也夠復雜了吧,還是不是成功了,而且魚和熊掌不可兼得。有時候服務器端也不一定要實現所有東西,可以把一些邏輯交給客戶端去做。比如顯示,Rest里顯示是完全交給客戶端去處理的,服務器只管數據的存儲,不管客戶端是網頁,還是一個手機應用程序,還是另外一個企業應用。各種各樣的客戶端進來,他們會有各種各樣的需求,服務器端不可能一一滿足,只能客戶端使用統一的API去組合,實現自己的需求。
3. 規范URL的使用
好了,對資源的操作統一了,但是客戶端還是要知道怎么觸發對資源的某個具體的操作。Rest用URL的規范來保證這種統一性。
創建并保存一個博客:
[plain] view plaincopy
這個請求需要返回博客的保存后的結果,其中包括博客的標識(ID)。 獲取一個已經保存的博客,并更新它:
[plain] view plaincopy
這個博客的標識是345。獲取博客的某個回復:
[plain] view plaincopy
對待子資源,通常的做法就是和這個例子一樣,是一級一級的往下找。我們還可以有其他方法,比如remove用來刪除,merge用來部分更新,list用來查找。
有三種方式可以將參數傳給API操作:
第一種是通過URL的地址傳遞,如前面的例子中把標識放在URL里;
第二種是通過URL的參數,比如,對于一個查找請求,可以把查找的過濾條件放在參數里:
[plain] view plaincopy
第三種是PUT或者POST請求的時候,把內容放在HTTP body里面。這里通常就是博客的內容。
前面我們的例子中有些請求是GET,有些是POST,其實這是有原則的。通常對資源內容沒有改變的操作都實用GET,比如獲取資源,查找資源;對資源有改變的操作都用POST,比如保存資源。
如果想做的更好,我們應該近一步的使用HTTP的請求方法,直接把HTTP方法和要做的操作映射起來。比如我喜歡認為GET請求就是獲取資源(get),PUT方法就是更新整個內容(save,update,我覺得這兩個沒必要區分),POST方法就是更新部分內容(merge),DELETE方法就是刪除資源(remove)。如果這樣的話,請求的URL又能簡化:
[plain] view plaincopy
當然對于list操作,這里就沒法滿足了,還是需要在URL層面上做些區別。
對于merge操作,有很多人認為是不必要的,Rest不應該提供這個API,但是我覺得在某些情況下很有用。比如某個資源對象,它的內容在不斷的擴充,怎么讓老的客戶端在內容擴充后還能繼續使用呢? 如果我們要求所有更新請求都必須把所有內容都放在請求的body中,對于客戶端來說就不是那么好做了,但是如果我們允許merge請求,客戶端可以可以完全忽略新增加的字段,而只把自己知道的字段放在請求內容中即可。
4. 資源的多重表述
這一步我覺得不是必須的。
Rest里,資源的內容通常直接作為一段JSON或者XML返回給客戶端。資源多重表述指的是,一個資源應該能夠支持根據客戶端的請求,返回相應的格式給客戶端。服務器應該按照請求HTTP頭中的Accept屬性決定返回格式。比如對于Ajax請求,Accept頭是application/json,服務端返回JSON格式;對于android請求,Accept頭是application/xhtml+xml,服務器返回XML格式。
我覺得這一步不是必須的因為至少從項目前期來說,我們應該都只會支持一種格式。資源的多重表述給我們一種處理多重請求格式的方式,但是我們不需要一開始就支持它。
5. 進一步合理利用HTTP
前面我們已經應用了HTTP的一些東西,比如請求方法,Accept頭。事實上我們可以利用更多。
HTTP支持客戶端緩存,在HTTP響應里利用Cache-Control,Expires,Last-Modified三個頭字段,我們可以讓瀏覽器緩存資源一段時間。Rest也可以利用這些頭,告訴客戶端在一定時間內不需要再次請求資源。這對提高性能有很大好處。更多HTTP頭信息,可以參考http://en.wikipedia.org/wiki/List_of_HTTP_header_fields。
Rest的請求會出錯,HTTP的請求也會出錯。我們可以直接利用HTTP的response code來告訴客戶端Rest請求出了什么錯誤。比如500,告訴客戶端,服務器出錯了;401告訴客戶端需要把安全驗證信息附上,需要登錄系統;404告訴請求的資源不存在,等等。更多HTTP響應碼,可以參考http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html。在實際的業務中,HTTP的那些response code肯定是不能滿足所有需求的,適當的在response body中加上更詳細的錯誤信息也是必須的。
還有其他很多,總之能利用上的就利用上,不比再次發明輪子。
6. 實現請求的無狀態
Rest是無狀態的。Rest的請求之間不應該有依賴,在調用一個請求前,不需要一定要去提前調用另外一個請求。Rest里面不應該有session,特別是Rest請求不應該保存信息在sesssion里,以便在后面的調用中使用。甚至包括安全驗證,客戶端不應該需要提前登錄,然后把權限信息保存在session里,后面的請求用同一個session來調用。
實現無狀態的方法就是,把所有信息都包含在當前的請求中,包括驗證信息。HTTP是無狀態的,HTTP里有一個Authorization頭,HTTP的要求是在每次請求的時候都把驗證信息放在里面,服務器每次處理請求前都去驗證這個信息。為了安全,我們可以提供一個生成token的Rest API,客戶端調用這個API生成token(可以附上用戶名/密碼來生成token)。在后面的所有請求中都把這個token放在Authentication頭中。
實現無狀態最大的好處是能夠方便的擴展服務器,也即scalability。否則的話,我們要么把Session綁定到具體服務器上,要么用一個共享的空間存儲Session。而實現無狀態后,我們可以隨意增加,減少服務器數量,都不會對當前用戶造成影響。
質文章,第一時間送達!
在本教程的這里,我將向您展示如何在Django REST框架中使用Swagger API。Swagger API為REST API端點提供了結構良好的文檔,因此新手可以說如何在不了解其內部實現的情況下測試REST API。
本質上,Swagger做的是簡單但非常強大的事情:通過添加一些附加注釋,它會生成REST API描述,例如HTTP方法,路徑/查詢/表單參數,響應,HTTP錯誤代碼等),甚至提供了一個簡單的Web UI來對您的API的REST調用。
Swagger規范是描述RESTful API的強大定義格式,它創建RESTful接口,通過有效地映射與之關聯的所有資源和操作來輕松開發和使用API。它易于學習,與語言無關,并且可以人工和機器可讀。
先決條件
Python 3.8.5,Django 3.0.8,REST框架(pip install djangorestframework),Swagger(pip install django-rest-swagger)
假定您已經在系統上安裝并配置了Python。
下一個任務是安裝Django。首選方法是使用命令pip install Django進行安裝。您可以閱讀有關Django安裝的更多詳細信息。
我們將使用MySQL數據庫服務器作為存儲數據的持久系統,因此您需要閱讀教程,了解如何使用django設置MySQL以執行SQL語句。
另外,您需要使用命令pip install django-rest-swagger安裝Swagger模塊。
我建議您先閱讀Django MySQL REST CRUD API示例教程,然后再繼續學習。因為此示例恰好遵循該教程。在此示例中,除了REST API CRUD示例之外,我還添加了Swagger API。
在本示例中,我將不展示項目的每個部分,因為我將與現有項目一起工作,但是我將介紹重要的更改。您以后總是可以從本教程底部的鏈接從我的Github帳戶下載完整的項目。
項目設置
我們需要做的第一件事是創建項目目錄。項目名稱為djangomysqlrestcrudswagger,我們將使用以下命令創建該項目。
<span class="code-snippet_outer">django-admin startproject djangomysqlrestcrudswagger</span>
下一步是在項目內部創建一個應用程序以執行CRUD操作。使用以下命令創建一個名為restcrudswagger的應用程序。
<span class="code-snippet_outer">django-admin startapp restcrudswagger</span>
現在,我們需要將此restcrudswagger應用程序添加到項目中。因此,編輯文件djangomysqlrestcrudswagger / djangomysqlrestcrudswagger / settings.py并將以下行添加到INSTALLED_APPS部分:
<span class="code-snippet_outer"><span class="code-snippet__attribute">INSTALLED_APPS</span>=[</span></code><code><span class="code-snippet_outer"> ...</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">'rest_framework_swagger'</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">'restcrudswagger.apps.RestcrudswaggerConfig'</span>,</span></code><code><span class="code-snippet_outer">]</span>
上一行是使用文件djangomysqlrestcrudswagger / restcrudswagger / apps.py構成的。您將在此文件中看到名為=’restcrudswagger’的RestcrudswaggerConfig類。
您需要將以下行添加到上述文件(settings.py)中,否則您將看到錯誤“ /’AutoSchema’對象的AttributeError沒有屬性’get_link’”。
<span class="code-snippet_outer"><span class="code-snippet__attr">REST_FRAMEWORK</span>={ <span class="code-snippet__string">'DEFAULT_SCHEMA_CLASS'</span>: <span class="code-snippet__string">'rest_framework.schemas.coreapi.AutoSchema'</span> }</span>
URLS
接下來,我將更改URL方案以添加用于REST文檔的Swagger API。將以下代碼寫入文件 djangomysqlrestcrudswagger / djangomysqlrestcrudswagger / urls.py中。
<span class="code-snippet_outer"><span class="code-snippet__keyword">from</span> rest_framework_swagger.views <span class="code-snippet__keyword">import</span> get_swagger_view</span></code><code><span class="code-snippet_outer"></span></code><code><span class="code-snippet_outer">schema_view=get_swagger_view(title=<span class="code-snippet__string">'User API'</span>)</span></code><code><span class="code-snippet_outer"></span></code><code><span class="code-snippet_outer">urlpatterns=[</span></code><code><span class="code-snippet_outer"> url(<span class="code-snippet__string">'^$'</span>, schema_view)</span></code><code><span class="code-snippet_outer">]</span>
帶有源代碼的整個文件如下:
<span class="code-snippet_outer"><span class="code-snippet__keyword">from</span> django.urls <span class="code-snippet__keyword">import</span> include, path</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">from</span> rest_framework <span class="code-snippet__keyword">import</span> routers</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">from</span> restcrudswagger <span class="code-snippet__keyword">import</span> views</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">from</span> django.conf.urls <span class="code-snippet__keyword">import</span> url</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">from</span> rest_framework_swagger.views <span class="code-snippet__keyword">import</span> get_swagger_view</span></code><code><span class="code-snippet_outer"></span></code><code><span class="code-snippet_outer">router=routers.DefaultRouter</span></code><code><span class="code-snippet_outer">router.register(<span class="code-snippet__string">r'users'</span>, views.UserViewSet)</span></code><code><span class="code-snippet_outer"></span></code><code><span class="code-snippet_outer">schema_view=get_swagger_view(title=<span class="code-snippet__string">'User API'</span>)</span></code><code><span class="code-snippet_outer"></span></code><code><span class="code-snippet_outer">urlpatterns=[</span></code><code><span class="code-snippet_outer"> url(<span class="code-snippet__string">'^$'</span>, schema_view),</span></code><code><span class="code-snippet_outer"> url(<span class="code-snippet__string">r'^'</span>, include(router.urls))</span></code><code><span class="code-snippet_outer">]</span>
Swagger UI Template
接下來,您需要創建Swagger模板文件,該文件將在您訪問URL時呈現。
以下內容被寫入djangomysqlrestcrudswagger / restcrudswagger / templates / rest_framework_swagger / index.html。
<span class="code-snippet_outer"><span class="code-snippet__meta"><!DOCTYPE html></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"><<span class="code-snippet__name">html</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">head</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">title</span>></span>Swagger<span class="code-snippet__tag"></<span class="code-snippet__name">title</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">meta</span> <span class="code-snippet__attr">charset</span>=<span class="code-snippet__string">"utf-8"</span>/></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">meta</span> <span class="code-snippet__attr">name</span>=<span class="code-snippet__string">"viewport"</span> <span class="code-snippet__attr">content</span>=<span class="code-snippet__string">"width=device-width, initial-scale=1"</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">link</span> <span class="code-snippet__attr">rel</span>=<span class="code-snippet__string">"stylesheet"</span> <span class="code-snippet__attr">type</span>=<span class="code-snippet__string">"text/css"</span> <span class="code-snippet__attr">href</span>=<span class="code-snippet__string">"http://unpkg.com/swagger-ui-dist@3/swagger-ui.css"</span> /></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"></<span class="code-snippet__name">head</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">body</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">div</span> <span class="code-snippet__attr">id</span>=<span class="code-snippet__string">"swagger-ui"</span>></span><span class="code-snippet__tag"></<span class="code-snippet__name">div</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">script</span> <span class="code-snippet__attr">src</span>=<span class="code-snippet__string">"http://unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js"</span>></span><span class="code-snippet__tag"></<span class="code-snippet__name">script</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">script</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">const</span> ui=SwaggerUIBundle({</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">url</span>: <span class="code-snippet__string">"{% url schema_url %}"</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">dom_id</span>: <span class="code-snippet__string">'#swagger-ui'</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">presets</span>: [</span></code><code><span class="code-snippet_outer"> SwaggerUIBundle.presets.apis,</span></code><code><span class="code-snippet_outer"> SwaggerUIBundle.SwaggerUIStandalonePreset</span></code><code><span class="code-snippet_outer"> ],</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">layout</span>: <span class="code-snippet__string">"BaseLayout"</span></span></code><code><span class="code-snippet_outer"> })</span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"></<span class="code-snippet__name">script</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"></<span class="code-snippet__name">body</span>></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"></<span class="code-snippet__name">html</span>></span></span>
已知問題
如果在訪問URL http:// localhost:8000時看到以下錯誤,則可以編輯路徑中提到的以下文件,如下圖所示:
Replace the line {% load staticfiles %} by {% load static %} at line 2.
部署應用
現在,我準備測試構建的API。讓我們使用manage.py runserver從命令行啟動服務器。該應用程序將在默認端口8000上運行。如果要更改服務器的默認主機/端口,則可以在此處閱讀教程。
測試應用
現在,如果您正確地遵循了教程,那么在訪問URL http:// localhost:8000時,您將在瀏覽器上看到以下屏幕:
來源:https://www.roytuts.com/how-to-use-swagger-with-python-based-django-rest-apis/
回復下方「關鍵詞」,獲取優質資源
回復關鍵詞「 pybook03」,立即獲取主頁君與小伙伴一起翻譯的《Think Python 2e》電子版
回復關鍵詞「入門資料」,立即獲取主頁君整理的 10 本 Python 入門書的電子版
回復關鍵詞「m」,立即獲取Python精選優質文章合集
回復關鍵詞「book 數字」,將數字替換成 0 及以上數字,有驚喜好禮哦~
題圖:pexels,CC0 授權。
ETL,全稱為Extract-Transform-Load,即數據提?。‥xtract)、數據轉換(Transform)和數據加載(Load)。這是數據倉庫中數據處理的重要過程。ETL過程中,數據從源系統被提取出來,然后經過清洗、轉換和集成等操作,最后加載到目標系統(通常是數據倉庫或數據湖)。
ETL的主要目標是將企業中的分散、異構數據集成到一起,為企業的決策提供支持。通過ETL過程,企業可以實現數據的統一視圖,提高數據的質量和一致性。
RESTful API是一種軟件架構風格,它是一種基于HTTP協議、XML(或JSON、HTML等)數據格式、URI等技術來設計的網絡應用程序接口。RESTful API的設計原則是簡單、直觀、標準化,使得API易于使用、易于理解和易于擴展。
在RESTful API中,每個URL代表一種資源。客戶端和服務器之間,傳遞這種資源的某種表現層??蛻舳送ㄟ^四個HTTP動詞,對服務器端資源進行操作,實現"表現層狀態轉換"。
ETL和RESTful API在許多場景中都有廣泛的應用。例如,在數據倉庫建設、數據集成、數據清洗、數據遷移、系統集成、微服務架構等方面,都有ETL和RESTful API的身影。
特別是在云計算和大數據時代,數據量激增,數據類型多樣,數據源分散,這就需要更強大、更靈活的工具來處理數據。而ETL和RESTful API正好可以滿足這些需求。
使用ETL工具實現RESTful API有很多好處。首先,ETL工具通常提供了豐富的數據連接器,可以連接各種類型的數據源,包括數據庫、文件、消息隊列、API等。這意味著,我們可以通過ETL工具,方便地從RESTful API中提取數據。
其次,ETL工具通常提供了強大的數據轉換功能,包括數據清洗、數據轉換、數據聚合等。這意味著,我們可以通過ETL工具,對從RESTful API中提取的數據進行深度處理。ETL工具通常提供了可視化的操作界面,使得數據處理過程更加直觀、易懂。這意味著,我們可以通過ETL工具,更好地理解和控制數據處理過程。
最后、ETL工具通常提供了任務調度、監控、告警等功能。這意味著,我們可以通過ETL工具,更好地管理和維護數據處理任務。
下面,我們以一個具體的ETL工具--ETLCLoud為例,展示如何使用ETL工具實現RESTful API的數據提取和處理。
在流程設計中,我們選擇RESTful API作為數據源。我們輸入API的URL,選擇合適的HTTP方法(如GET或POST),并設置好請求頭和請求參數。
配置好后可以測試請求數據:
配置數據過濾組件,過濾出年齡在50到100之間的信息
最后,我們在ETL工具中設置數據加載的目標。我們可以選擇將數據加載到數據庫、文件、消息隊列等目標中。我們這里配置庫表輸出組件,設置輸出目標庫。
保存后運行流程
查看目標庫表數據:
通過以上步驟,我們就完成了一個ETL任務的配置。我們可以運行這個任務,查看任務的運行狀態和結果。如果任務運行出現問題,我們還可以通過ETL工具的監控和告警功能,及時發現和處理問題。
總的來說,ETL和RESTful API是數據處理的重要工具。通過ETL工具,我們可以方便地從RESTful API中提取數據,進行深度處理,然后加載到目標系統。ETL工具的豐富功能和易用性,使得數據處理變得更加簡單、高效。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。