什麼是REST API? REST全名Representational State Transfer,中文譯作表徵性狀態傳輸,嗯…我們很難從名字理解這是什麼東西。
REST其實是一種風格架構,通常是透過HTTP協定進行通訊,Client端透過HTTP request提出對於Server端資源的操作請求,資源的操作包括取得、建立、修改和刪除(就是俗稱的CRUD,Create、Retrieve、Update、Delete),Sever端也會以HTTP回應資源,資源通常以JSON或XML表示。
HTTP協定中的每一個request都是獨立,stateless特性讓Sever端與Client端低耦合,因此REST架構延展性佳,方便擴展新功能。Server端就負責維護資源狀態,Client端透過URI指定資源,使用HTTP協定提供的GET、POST、PUT和DELETE對映取得、建立、修改和刪除達到對資源的操作。
範例 (資料來源:WIKI):
資源
|
GET
|
PUT
|
POST
|
DELETE
|
一組資源的URI,比如https://example.com/resources/
|
列出URI,以及該資源組中每個資源的詳細資訊(後者可選)。
|
使用給定的一組資源替換目前整組資源。
|
在本組資源中建立/追加一個新的資源。該操作往往返回新資源的URL。
|
刪除整組資源。
|
單個資源的URI,比如https://example.com/resources/142
|
取得指定的資源的詳細資訊,格式可以自選一個合適的網路媒體類型(比如:XML、JSON等)
|
替換/建立指定的資源。並將其追加到相應的資源組中。
|
把指定的資源當做一個資源組,並在其下建立/追加一個新的元素,使其隸屬於目前資源。
|
刪除指定的元素。
|
HTTP狀態碼:
- 200 OK:成功
- 204 No Content:成功,但回應沒有資料,通常是DELETE請求的回傳
- 400 Bad Request:請求本身有錯
- 401 Unauthorized:無授權
- 404 Not Found:找不到想要的資源
- 405 Method Not Allowed:該資源不支援這個HTTP動作
- 409 Conflict:代表更新系統狀態時出現衝突
- 500 Internal Server Error:伺服器內部錯誤
- 503 Service Unavailable:伺服器暫時無法提供服務
在介紹如何使用Google Cloud Endpoints之前,不知各位有沒有跟我一樣的疑問,我們之前做的以webapp2提供的RequestHandler不就能處理HTTP傳輸,何必還要使用Cloud Endpoints,而在stackoverflow也有類似的發問(https://stackoverflow.com/questions/24211737/google-cloud-endpoints-vs-normal-request-handlers-for-small-webapps),可以看看,總之Cloud Endpoints有它的好處像是有監控後台以及支援library之類的。
Google Cloud Endpoints服務提供我們開發、部署、保護和監控REST API。 部屬API在Cloud Endpoints上有三種做法 (參考:https://cloud.google.com/endpoints/docs/quickstart-endpoints):
- Endpoints OpenAPI
- Endpoints gRPC
- Endpoints Framework
Cloud Endpoints以Google Protocol RPC Library為根基,這是一套在HTTP協定之上實作RPC服務的軟體開發框架。運作上從請求接收某一訊息類型的物件,在回應裡回傳另一訊息類型,訊息類型繼承自protorpc.messages.Message,而服務則繼承自protorpc.remote.Service。
目前Google App Engine改採用Cloud Endpoints Frameworks 2.0,1.0版的方法是不建議使用了,架設Cloud Endpoints Frameworks 2.0環境的方法請看這:遷移到 Cloud Endpoints Frameworks 2.0 版,大致上就是先下載google-endpoints函式庫再做app.yaml libraries設定。
那下面我們就以官方提供的echo api作為例子,功能就是client端送字串與一n值,server會回傳重複n次的字串回來。Code可參考這:https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/appengine/standard/endpoints-frameworks-v2/echo,下面有經過簡化。 app.yaml:
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /_ah/api/.*
script: main_api.api
libraries:
- name: pycrypto
version: 2.6
- name: ssl
version: 2.7.11
main_api.py:先定義訊息類別,有點像在定義ORM model,會定義欄位與型別,欄位參數內有一整數,這個整數是識別碼,在訊息類別內必須獨一無二。
import endpoints
from endpoints import message_types
from endpoints import messages
from endpoints import remote
# [START messages]
class EchoRequest(messages.Message):
message = messages.StringField(1)
class EchoResponse(messages.Message):
message = messages.StringField(1)
ECHO_RESOURCE = endpoints.ResourceContainer(
EchoRequest,
n=messages.IntegerField(2, default=1)
)
# [END messages]
* 如果要求包含路徑或查詢字串引數(query string arguments),請使用適當的ResourceContainer 取代 Message 類別。看下面的request,n在URL路徑後加上?n=...表示值。
main_api.py:加入服務
@endpoints.api(name='echo', version='v1')
class EchoApi(remote.Service):
@endpoints.method(
ECHO_RESOURCE, # 求用的訊息類別
EchoResponse, # 回應中的訊息類別
path='echo',
http_method='POST',
name='echo') # 代表端點名的字串
def echo(self, request):
output_message = ' '.join([request.message]*request.n)
return EchoResponse(message=output_message)
* 請求path會是這樣:/_ah/api/[name]/[version]/[path]
* 如果要求主體中未顯示引數 (例如在 GET 要求中),您可以省略要求的 Message 類別,只使用 message_types.VoidMessage 值。
或是
@endpoints.method(
ECHO_RESOURCE,
EchoResponse,
path='echo/{n}',
http_method='POST',
name='echo_path_parameter')
def echo_path_parameter(self, request):
output_message = ' '.join([request.message]*request.n)
return EchoResponse(message=output_message)
如此輸入 /_ah/api/echo/v1/echo/3,n會等於3最後別忘記要開啟api server,在main_api.py後加上程式碼。
main_api.py:
# [START api_server]
api = endpoints.api_server([EchoApi])
# [END api_server]
Local測試: 1. dev_appserver.py app.yaml
2. 瀏覽器輸入 http:localhost:8080/_ah/api/explorer 會看到Google API Explorer
你大概會看到兩個警告,一個是說這個網站已經過時現在改用Cloud Endpoints Portal,另一個則是HTTP安全性問題,這些暫且不管,我們還是能試用我們完成的API。
3. 點 echo API再點echo.echo,就可以輸入測試,點選Execute without OAuth執行。
4. 另外你也可以透過window cmd來送出請求,打上這樣的命令:curl -X POST -H "Content-type: application/json" -d "{\"message\": \"hello\"}" http://localhost:8080/_ah/api/echo/v1/echo?n=3 ( \ :跳脫字元;^&:^可用來跳脫&)
也試試echo_path_parameter
題外話,其實試了一下message也可放在URL中,n也可放body中,會優先body的值。
參考資料:
1. 官方資料:https://cloud.google.com/endpoints/docs/frameworks/python/create_api
2. 雲端網頁程式設計:Google App Engine使用Python (博碩文化出版)
沒有留言:
張貼留言