輕鬆學習 Python：使用 Flask 創建 Web API
By: Yao-Jen Kuo
Tags: Data, Flask, Python, API

關於 API

API（Application Programming Interface） 指的是一段程式碼與作業系統、與其他段程式碼彼此之間溝通的管道，如果我們曾經聽過這個名詞，有很高機率它指的其實是特定類型 API，像是建構於網站應用程式的 API、作業系統的 API、資料庫系統的 API、電腦硬體的 API 或者軟體應用程式的 API。在這個小節我們專注在建構於網站應用程式的 API 類型，即 Web API。

試想在一個資料科學團隊中，不同角色依據職務屬性，有著各自慣用的開發環境與程式語言，像是熟悉寫作 R、Julia 的統計學家、熟悉寫作 Python、Scala 的資料工程師、熟悉寫作 JavaScript 的商業儀表板前端工程師，在一個需要彼此合作的專案中，Web API 可以有效地讓各個工作流透過網路呼叫彼此的程式並回傳結果。

使用 Web API 的好時機

Web API 是讓團隊其他成員與使用者分享資料的其中一種方式，並不是唯一方式、也不一定是最佳方式。如果我們所提供出來的資料較小且不會頻繁隨時間而更動，提供靜態的 JSON、XML 或 CSV 等常見文字格式資料集可能是更好的選擇，然而當資料具備下列特性時，使用 Web API 分享就顯得比使用文字格式資料集提供下載來得更好。

資料更新的速度快、頻率高，生成靜態資料集檔案過於緩慢

使用者可能只需要龐大資料中的一個子集（subset）

資料具備重複運算的特性（例如 rolling stats）

Web API 相關術語

在使用或者創建 Web API 的時候常會遭遇到下列幾個名詞，稍微暸解它們的定義對於使用與創建 Web API 將有很大程度的幫助。

HTTP（Hypertext Transfer Protocol）：超文本傳輸協議是網際網路傳輸資料的基礎，HTTP 利用不同的方法（methods）實現使用者和網站之間請求（request）與回覆（response）的標準，這些標準定義了資料移動的方向與預期會發生的結果，常見的兩種方法是從伺服器獲取資料的 GET 方法與將新的資料傳送給伺服器的 POST 方法。

URL（Uniform Resource Locator）：即俗稱的網址，是網站在網際網路上的門牌號碼，我們通常利用瀏覽器輸入網址藉此對網頁伺服器發出 GET 方法請求資料。

JSON（JavaScript Object Notation）：JavaScript 物件表示法是一種輕量級的資料結構，雖然由 JavaScript 起源但很多的程式語言都支持 JSON 格式資料的創建與解析，舉例來說，JSON 以物件（object）與陣列（array）為其資料結構的核心，而這兩者可以分別完美呼應 Python 的字典（dict）與清單（list）。

REST（Representational State Transfer）：REST 是描述 Web API 最佳實踐方式的哲學，遵循 REST 所設計出來的 Web API 就能夠被稱呼為 REST API。

前置準備

我們將使用 Python 3、Flask 創建一個 Web API 來分享一個經典的資料集 gapminder，首先建立一個 Python 3 的工作環境稱為 flask 並安裝 Flask 與 pandas 套件（這裡使用到輕鬆學習 Python：conda 的核心功能所介紹的技巧）。

## Collecting package metadata: done

## Solving environment: done

##

## ## Package Plan ##

##

## environment location: /Users/kuoyaojen/anaconda3/envs/flask

##

## added / updated specs:

## - flask

## - pandas

## - python=3

## # packages in environment at /Users/kuoyaojen/anaconda3/envs/flask:

## flask 1.0.2 py37_1

在使用者目錄下新增資料夾 gapminder-api，切換至該路徑後下載 gapminder.csv 資料，並且創建空白檔案 api.py。

## % Total % Received % Xferd Average Speed Time Time Time Current

## Dload Upload Total Spent Left Speed

## 100 88760 100 88760 0 0 225k 0 --:--:-- --:--:-- --:--:-- 225k

## gapminder.csv

除了創建與啟動工作環境之外，新增資料夾與下載 gapminder.csv 亦可以用電腦的圖形化使用者介面完成。

創建一個 Flask 應用程式

Python 有許多能用於創建 Web 應用程式和 Web API 的框架，其中最著名的是 Django，Django 是具有固定專案架構並包含許多內建工具的框架，對於有經驗的網站工程師來說可以有效節省開發功能的時間和精力，但對於我們的需求可能略顯得「殺雞使用牛刀」，相對來說輕量的 Flask 框架也能勝任Web API 的需求：管理 HTTP 請求和顯示資料內容。

以習慣使用的文字編輯器（例如：Visual Studio Code）在 api.py 中寫入基礎的 Flask 網頁應用程式：

存檔之後回到命令列，輸入 python api.py 啟動 Web 應用程式，並依照畫面提示打開瀏覽器前往 http://127.0.0.1:5000/。



## * Environment: production

## WARNING: Do not use the development server in a production environment.

## Use a production WSGI server instead.

## * Debug mode: on

## * Running on

## * Restarting with stat

## * Debugger is active!

## * Debugger PIN: 133-968-406 ## * Serving Flask app "api" (lazy loading)## * Environment: production## WARNING: Do not use the development server in a production environment.## Use a production WSGI server instead.## * Debug mode: on## * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)## * Restarting with stat## * Debugger is active!## * Debugger PIN: 133-968-406

Hello Flask!

建立分享資料的 Web API：手動輸入

在我們搭建的 Web API 中，資料以多個 Python dict 所組成的 list 加入，接著手動輸入一些資料測試，像是城市（台北、紐約與倫敦）的簡單資訊，Python 的 list of dictionaries 可以藉由 Flask 套件所提供的 jsonify() 函數輸出為 JSON 格式呈現在網頁上。

/cities/all 顯示所有城市的簡單資訊

接著將城市與國家名稱更改為繁體中文試試能否正常運作，會發現中文的資料改以 ASCII 編碼的外觀顯示。

更改為繁體中文後會呈現為 ASCII 編碼

解決方式是在 Flask 應用程式中加入 app.config["JSON_AS_ASCII"] = False 的參數設定。

加入 app.config["JSON_AS_ASCII"] = False 的參數設定

建立分享資料的 Web API：以 pandas 讀入 CSV 檔案

測試過手動建立資料後，我們試著用 pandas 套件讀入 gapminder.csv 並將它加入 Web API 中，由於 pandas 讀入 .csv 檔案會以資料框結構儲存，傳送給 jsonify() 函數的資料應該要如同手動建立以 list of dictionaries 的形式才是正確輸入格式，於是以迴圈將資料框的每一筆觀測值的變數名稱與資料值分別對應成 dict 的 Key 與 Value 再存入 list 中，最後傳入 jsonify() 函數作為輸入。

但啟動 Web 應用程式後卻出現 TypeError: Object of type int64 is not JSON serializable 錯誤。

出現 TypeError: Object of type int64 is not JSON serializable 錯誤

這是因為在將觀測值由資料框取出來的時候是 pd.Series 的資料結構，裡頭的整數資料型態並不是 Python 的 int 而是 NumPy 中的 numpy.int64 ；同理浮點數資料型態也不是 float 而是 numpy.float64 ，因此加入考慮資料型態的轉換來解決。

加入考慮資料型態的轉換

建立分享資料的 Web API：讓使用者查詢指定內容

目前使用者從 cities/all 或 gapminder/all 都只能瀏覽整個 list of dictionaries，當分享資料的數量不斷更新、增加，目前的設計就會顯得不太合適，因此我們可以利用 Flask 框架所提供的 request 模組加入 cities?city_name= 或者 gapminder?country= 這兩個 routes 藉此讓使用者能更精準地向 Web API 索取指定資料。

http://127.0.0.1:5000/cities?city_name=台北

http://127.0.0.1:5000/gapminder?country=Taiwan

http://127.0.0.1:5000/cities?city_name=台北

我們對於創建本機端的 Web API 已經有了初步認識，但還有像是資料庫的連接、 Web API 設計的常見準則與部署到雲端伺服器上等更深入的相關知識值得研究，將在之後的章節繼續探討。

小結

在這個小節我們簡介如何以 Python 的框架 Flask 在本機（localhost）設置簡單的 Web API 來分享手動創建的資料 cities（是一個 list of dictionaries）與現成的 CSV 檔案 gapminder.csv（以 pandas 讀入為 DataFrame），並暸解如何解決繁體中文顯示、NumPy 資料型態以及查詢部分資料集的問題。