PythonでWebAPI作ってみた
はじめに
はじめまして。新卒エンジニアです。
PythonでAPIを作る経験をしてみたい、そう感じ今回記事を書かせていただきました。
REST API
APIを作成するにあたって、REST APIについて学習しました。
サイトの内容を簡単にまとめると
RESTは「RESTの4原則に沿ったシンプルな設計思想」のことで、
①統一インターフェース
②アドレス可能性
③接続性
④ステートレス性
の4つ。
これらに沿ったシステムを「RESTfulなシステム」という。
すなわち「REST API」とはRESTの4原則に則ったAPIのことです。
今回は、この考え方を用いてAPIを作成していきます。
FastAPI
今回は、PythonのフレームワークであるFastAPIを用いて作成していきます。
FastAPI は、Pythonの標準である型ヒントに基づいてPython 3.6 以降でAPI を構築するための、モダンで、高速(高パフォーマンス)な、Web フレームワークです。
日本語ドキュメントが豊富で、理解しやすいように感じたため採用させていただきました。
実装
FastAPI導入
はじめにFastAPIをインストールします。
uvicorn(ユーブイアイコーン)とは、Python用の「ASGI Webサーバ」実装のことで、非同期対応 Python Web サーバー、フレームワーク、およびアプリケーション間の標準インターフェースを提供することを目的としています。
pip install fastapi uvicorn
コード
# FastAPIの読み込み
from fastapi import FastAPI
from pydantic import BaseModel
import math
class TaxIn(BaseModel):
price: int
item: str = None
tax_rate: float
# FastAPIのインスタンスを作成
app = FastAPI()
# getメソッドで、/にアクセスした時の処理を記述
@app.get("/")
# asyncで*非同期処理を行う
# *あるタスクを実行している最中に、実行中のタスクを止めることなく、別のタスクを実行できる
async def hello():
return {"text": "Hello World!"}
# getメソッドで、/TaxEx/{price}にアクセスした時の処理を記述
@app.get("/TaxEx/{price}")
async def TaxEx(price: int, item: str = None):
if item:
return {"text": f"{item}は{price}円"}
return {"text": f"何かが{price}円"}
# postメソッドで、/にアクセスした時の処理を記述
@app.post("/TaxIn")
async def TaxIn(data: TaxIn):
in_tax_cost = math.ceil(data.price * (1 + data.tax_rate))
return {"text": f"{data.item}は{in_tax_cost}円(税込み)"}
簡易的に、getで開いた場合、そしてget・post共に値を受け取る挙動を確認しました。
import
# FastAPIの読み込み
from fastapi import FastAPI
from pydantic import BaseModel
import math
ここでは必要要素をimportしており、BaseModelとは型の指定によりデータのバリデーションを行っています。
class TaxIn(BaseModel):
price: int
item: str = None
tax_rate: float
実際には、上記のclassを作成する際に使用しています。
このclassは、postで受け取るデータの型を指定するために作成しています。
FastAPIインスタンス
# FastAPIのインスタンスを作成
app = FastAPI()
ここでは、FastAPIのFastAPIクラスからappという名前のアプリケーションインスタンスを作成しています。
getメソッドで、/にアクセス
# getメソッドで、/にアクセスした時の処理を記述
@app.get("/")
# asyncで*非同期処理を行う
# *あるタスクを実行している最中に、実行中のタスクを止めることなく、別のタスクを実行できる
async def hello():
return {"text": "Hello World!"}
@app.get("/")デコレータを使用してルートエンドポイントを定義し、このエンドポイントへのHTTP GETリクエストが処理されるようになります。
async def hello()関数はこのエンドポイントのハンドラ関数で、リクエストが送信された際に実行され、JSONレスポンスを返します。
getメソッドでデータを受け取る
# getメソッドで、/TaxEx/{price}にアクセスした時の処理を記述
@app.get("/TaxEx/{price}")
async def TaxEx(price: int, item: str = None):
if item:
return {"text": f"{item}は{price}円"}
return {"text": f"何かが{price}円"}
getメソッドで、/にアクセスする場合とつくりは同じですが、/TaxEx/{price} のようにパス内に変数 {price} を含むことで、その部分がURL内の値として受け取ります。
関数の引数として price(整数)と item(オプションの文字列)を受け取ります。
/TaxEx/100:priceパラメーターが100で item パラメーターが指定されていない場合、{"text": "何かが100円"} のようなJSONレスポンスが返されます。
/TaxEx/200?item=コーヒー:price パラメーターが200で item パラメーターが"コーヒー"に設定されている場合、{"text": "コーヒーは200円"} のようなJSONレスポンスが返されます。
postメソッドでデータを受け取る
# postメソッドで、/にアクセスした時の処理を記述
@app.post("/TaxIn")
async def TaxIn(data: TaxIn):
in_tax_cost = math.ceil(data.price * (1 + data.tax_rate))
return {"text": f"{data.item}は{in_tax_cost}円(税込み)"}
関数の引数 data は TaxIn モデルのインスタンスとして受け取ります。このモデルは、POSTリクエストのボディから送信されたJSONデータを自動的にパースして作成されます。
このエンドポイントを使用するためには、POSTリクエストを /TaxIn に送信し、JSONデータをボディに含める必要があります。
実行
uvicorn main:app --reload
こちらを入力することで、ライブサーバーを実行します。
詳しくは、
- main: main.pyファイル
- app: main.py内部で作られるobject (app = FastAPI()の部分)
- --reload: コード変更時のサーバー再起動
チェック
ブラウザでhttp://localhost:8000を開くと
上記のようなレスポンスが表示されます。
次に、http://localhost:8000/docsを開くことで、下記のようなドキュメントを使用することができます。
ここで、getとpostの挙動を確認します。
getに渡した、urlに含まれた情報がうまくtextにわたっています。
postも渡したデータが、計算されtextにわたっています。
まとめ
今回はPythonのFastAPIを用いて、簡易的なWebAPIを作成しました。
コード自体も直感的で、理解しやすい部分が多くありました。
しかし、簡易APIを作っただけで、実際にフロントとの動作やFastAPIのメリットデメリットを深くまで理解できていないため、今後を続けて学習していきます。
今回はFastAPIでしたが、Flask・Django等そして別の言語でも挑戦していきたいと思います。
ご清聴ありがとうございました。
参考文献
Discussion