💸

PythonでWebAPI作ってみた

2023/09/11に公開

はじめに

はじめまして。新卒エンジニアです。
PythonでAPIを作る経験をしてみたい、そう感じ今回記事を書かせていただきました。

REST API

APIを作成するにあたって、REST APIについて学習しました。
https://tech.012grp.co.jp/entry/rest_api_basics
上記のサイトは、一つ一つかみ砕いて説明がしてあり、とても分かりやすかったです。
サイトの内容を簡単にまとめると

RESTは「RESTの4原則に沿ったシンプルな設計思想」のことで、
  ①統一インターフェース
  ②アドレス可能性
  ③接続性
  ④ステートレス性
 の4つ。
これらに沿ったシステムを「RESTfulなシステム」という。
すなわち「REST API」とはRESTの4原則に則ったAPIのことです。

今回は、この考え方を用いてAPIを作成していきます。

FastAPI

今回は、PythonのフレームワークであるFastAPIを用いて作成していきます。

FastAPI は、Pythonの標準である型ヒントに基づいてPython 3.6 以降でAPI を構築するための、モダンで、高速(高パフォーマンス)な、Web フレームワークです。

https://fastapi.tiangolo.com/ja/
日本語ドキュメントが豊富で、理解しやすいように感じたため採用させていただきました。

実装

FastAPI導入

はじめにFastAPIをインストールします。
uvicorn(ユーブイアイコーン)とは、Python用の「ASGI Webサーバ」実装のことで、非同期対応 Python Web サーバー、フレームワーク、およびアプリケーション間の標準インターフェースを提供することを目的としています。

pip install fastapi uvicorn

コード

main.py
# 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}円(税込み)"}

関数の引数 dataTaxIn モデルのインスタンスとして受け取ります。このモデルは、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等そして別の言語でも挑戦していきたいと思います。
ご清聴ありがとうございました。

参考文献

https://www.uvicorn.org/
https://fastapi.tiangolo.com/ja/tutorial/first-steps/
https://dev.classmethod.jp/articles/try_fastapi_intro/
https://aiacademy.jp/media/?p=988
https://qiita.com/yota_dev/items/ab8dea7f71c8a130d5bf

Discussion