--- title: Flask 建置 Resful API tags: Python description: Flask 建置Resful API筆記 --- # Flask 建置 Resful API 關於使用Docker建置映像檔與容器服務可參考 [使用Docker建置Nginx結合uWSGI映像檔](https://hackmd.io/CVdNFGTyTqKoMZRwauV2eg) [使用Docker運行Nginx與uWSGI容器服務](https://hackmd.io/0VSgSzPHTfaAfwcO3mVZ1Q) ## 下載專案包 https://github.com/s123600g/FlaskDemoNotes/tree/master/Restful_API 建立完成後請記得在專案目錄內新增一個uwsgi目錄,此為用來放置uWSGI運行Log檔案。 ## 下載Dockfile與建置Image Dockerfile: https://github.com/s123600g/FlaskDemoNotes/tree/master/Docker/Nginx_uWSGI_RestfulAPI 預設服務使用的Port為`8807`,如果需要更改請修改`Dockerfile`內 ```dockerfile= ENV web_port=8807 ``` 在終端機記得先切換位置至Dockerfle所在位置內,切換完後再建置Image ```shell= docker build -t nginx_flask_restfulapi_server:p8807 . ``` 如果要修改Image所顯示名稱與標籤,修改`-t`內`nginx_flask_restfulapi_server:p8807` ## 運行Docker容器服務 在終端機使用`docker run`指令建置容器服務運行 ```shell= docker run --name flask_restfulapi_base -p 8807:80 -v E:\Project\GitHub\FlaskDemoNotes\Restful_API:/web/web_data -d nginx_flask_restfulapi_server:p8807 ``` 記得要修改`-v`內`E:\Project\GitHub\FlaskDemoNotes\Restful_API`改成自己對應位置。 如果有修改`Dockerfile`內預設服務使用的Port,請將`-p`內`8807`改成自己設定的Port。 ## 測試容器服務是否正常運作起來 在瀏覽器打上 ``` http://localhost:8807/ ``` ![](https://i.imgur.com/4rPZDBJ.png) 這裡預設是顯示在`Server.py`內針對`"/"`路由位置內配置 ```python= @app.route("/", methods=['GET']) def index(): return "Restful API." ``` 主要用來測試容器服務掛載運作是否有起來,實際上主要API設置是在`Restful_API/FirstAPI.py`,詳細可參考下方框架配置說明。 ## 使用Postman測試 GET與POST ### GET ``` http://localhost:8807/firstapi?title=Hello ``` `Params`-->`title`(Key)-->`Hi`(Value) ![](https://i.imgur.com/z4ywyGC.png) ### POST ``` http://localhost:8807/firstapi ``` `Body` --> `raw` --> `JSON` JSON內容: ```json= { "title":"Hi", "value":"Hello!!" } ``` ![](https://i.imgur.com/wjIlEzj.png) ![](https://i.imgur.com/pBbhlmF.png) # 框架配置說明 API主體參數與實體配置檔案為`Startup.py` API模組放在`Restful_API/`內 --> `FirstAPI.py` 官方 Quickstart https://flask-restful.readthedocs.io/en/latest/quickstart.html ## 在`Startup.py`設置 1. 初始化 Flask Restful API 實體 ```python= api = Api(app) ``` 先建立Flask-RESTful API本體,之後所有API類別都會註冊給此本體作控管。 2. 匯入 Restful API Module ```python= from Restful_API.FirstAPI import FirstAPI ``` 將獨立API類別做為一個模組,可以自己自訂那些API負責做什麼事情。 3. 註冊 Restful API Module for Router ```python= api.add_resource(FirstAPI, '/firstapi',methods=['GET','POST']) ``` 將客製好的API模組給予註冊一個路由分配,透過指定路由來讓本體知道來自這一支路由請求該去哪一個模組處理請求。 ## 在`FirstAPI.py`設置 在實作一個API模組時,需要先匯入重要相關套件`Resource` ```python= from flask_restful import Resource ``` flask_restful Resource是我們實作模組基礎,也就是我們API類別繼承上層父類別,這一個最上層父類別幫我們實作了一些HTTP Method View基底,所以我們在模組繼承此類別後,可以直接實作針對Http Method View Function,在這Function名稱就是以使用Http Method來命名。 ```python= class API_Module_Name(Resource): # Http Method View Function def your_Http_Method_Name(self): pass ``` Http Method 可使用種類有 * GET * POST * PUT * DELETE 關於可使用Http Method View可參考 Method Views for APIs​: https://flask.palletsprojects.com/en/1.1.x/views/#method-views-for-apis 在官方說明中你可以看到提供簡單實作例子 https://flask-restful.readthedocs.io/en/latest/quickstart.html#a-minimal-api 在此API模組例子中,首先第一步先將模組類別繼承`Resource` ```python= class FirstAPI(Resource): ``` 內部簡單實作一個`dict_result` Dict物件作為簡單暫存空間,內部遵循以下資料結構 ``` { key:value } ``` ```python= dict_result = { "Hello":"Welcome", "Author":"jyu" } ``` 在完成繼承後,以此上層類別基礎實作兩種Http Method View Function,分別是`GET`與`POST` Http Method View Functionv - **GET** ```python= def get(self): # HTTP GET Action # get url argument - "title" get_web_arg_title = str(request.args.get("title")) response_result = dict() get_dict_result_key_list = [ key for key in self.dict_result.keys()] print(get_dict_result_key_list) if len(get_web_arg_title) != 0: # print(get_web_arg_title) # print( get_web_arg_title in get_dict_result_key_list) if get_web_arg_title in get_dict_result_key_list: # print(get_web_arg_title) response_result[str(get_web_arg_title)] = self.dict_result[str(get_web_arg_title)] # print(dict_result) # print(response_result) return jsonify(response_result) ``` 根據URL參數所傳遞參數`title`內容值作為`dict_result`簡單暫存空間取值依據,取出值後回傳給請求端作為回應結果。 取出URL參數 - **title** ```python= get_web_arg_title = str(request.args.get("title")) ``` 關鍵點在於`request`來自於 ```python= from flask import request ``` 使用 ```python= request.args.get() ``` 可參考 The Request Context https://flask.palletsprojects.com/en/1.1.x/reqcontext/ Http Method View Functionv - POST ```python= def post(self): # HTTP POST Action # Get JSON Data data = request.get_json(force=True) get_web_arg_title = str(data["title"]) get_web_arg_value = str(data["value"]) run_status = False response_result = dict() if len(get_web_arg_title) != 0: self.dict_result[str(get_web_arg_title)] = str(get_web_arg_value) run_status = True if run_status: response_result["status"] = "OK" response_result["msg"] = "Done." else: response_result["status"] = "Error" response_result["msg"] = "Add Failed." return jsonify(response_result) ``` 根據POST請求帶資料FormBody --> JSON內`title`與`value`各自對應value,來新增一筆資料紀錄在`dict_result`簡單暫存空間。 取出JSON資料 - **title**、**value** ```python= data = request.get_json(force=True) get_web_arg_title = str(data["title"]) get_web_arg_value = str(data["value"]) ``` 關鍵點在於`request`來自於 ```python= from flask import request ``` 使用 ```python= request.get_json() ``` 可參考 Incoming Request Data - get_json https://flask.palletsprojects.com/en/1.1.x/api/#flask.Request.get_json