Pythonのフレームワーク「FastAPI」をEC2で実装する
こんにちは、沖縄在住の下地です。コロナの影響でリモートワークになり早一ヶ月経ちました。家で業務をするというのは違和感はあるのですが通勤しなくて良いというのはとても魅力的だなと思い始めてます。
本日はPythonのフレームワークであるFastAPIについて興味がありEC2で実装したのでまとめたいと思います。
全体像
EC2でFastAPIを実装し、Amazon RDS(RDS)と接続し、CRUDのAPIを作成します。EC2とRDSは起動している状態からスタートします。
開発環境
環境としては以下の仕様で行います。
- python: 3.7.6
- sqlalchemy: 1.3.15
- OS: Amazon Linux 2 AMI (HVM), SSD Volume Type
- MySQL Community Edition: 5.7.22
EC2のセキュリティグループ設定
EC2でFastAPIを実装し確認するために、セキュリティグループは図に示すようにカスタムTCPタイプを選択し、ポート範囲を8000に設定します。
Python3系のインストール
EC2にpython3の環境を構築します。
$ sudo yum install python3 -y $ python3 -m venv my_app/env $ source my_app/env/bin/activate $ python --version -- pythonのversion確認 Python 3.7.6
FastAPIのインストール
最新のpipモジュールがインストールされているか確認し、FastAPIとDB接続に必要なライブラリをインストールします。
$ pip install pip --upgrade $ pip install fastapi $ pip install uvicorn
FastAPI実装
FastAPIのDocumentを参考にmain.py
を作成します。
EC2の外からアクセスできるように、host="0.0.0.0"
になるオプションを追記します。
import uvicorn from fastapi import FastAPI app = FastAPI() @app.get("/") def root(): return {"message": "Hello World"} @app.get("/items/{item_id}") def read_item(item_id: int, q: str = None): return {"item_id": item_id, "q": q} if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000)
python main.py
を実行します。
$ python main.py
下記のurlを実行するとFastAPIが動作していることがわかります。
(本来ならばEC2のIPv4の表記なのですが表記上、127.0.0.1
とします。)
http://127.0.0.1:8000/
http://127.0.0.1:8000/items/10?q=test
http://127.0.0.1:8000/docs
CRUD機能実装
EC2⇄RDSの接続設定
RDS操作に必要なライブラリをインストールします。
$ pip install sqlalchemy $ pip install pymysql
EC2からのMYSQLへのトラフィックを許可するために、RDSのセキュリティグループを変更します。
データベースを作成する
RDSに新規のデータベースを生成するcreate_db.py
を作成し実行します。
import sqlalchemy engine = sqlalchemy.create_engine('mysql+pymysql://user:password@RDS-Endpoint:3306') # サーバーと接続 dbname = 'db_fastapi' # db名 engine.execute('CREATE DATABASE %s' % dbname) #dbを作成
python create_db.py
データベースに必要な情報まとめ
このファイルにはデータベースの設定に必要な情報をまとめたファイルdatabase.py
を作成します。
from sqlalchemy import Column, Integer, String, create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base SQLALCHEMY_DATABASE_URI = "mysql+pymysql://user:password@RDS-Endpoint:3306/db_fastapi" engine = create_engine(SQLALCHEMY_DATABASE_URI, echo=True) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) Base = declarative_base() class Todo(Base): # Todoテーブルの定義 __tablename__ = 'todos' id = Column('id', Integer, primary_key = True) title = Column('title', String(200)) Base.metadata.create_all(bind=engine) # テーブル作成
database.py
を実行することでtodosテーブルが生成されます。
$ python database.py
CRUD機能を実装する
下記リンクを参考にCRUD機能を実装するようにmain.py
を修正します。
FastAPI|DB接続してCRUDするPython製APIサーバーを構築
import uvicorn from fastapi import Depends, FastAPI from sqlalchemy.orm import Session from pydantic import BaseModel from database import Todo, engine, SessionLocal app = FastAPI() class TodoCreate(BaseModel): # データの定義 title: str def get_db(): # リクエスト時にSessionLocalを作成し完了したら終了する try: db = SessionLocal() yield db finally: db.close() @app.get("/todos/") # すべてのtodoを取得する def read_todos(db: Session = Depends(get_db)): return db.query(Todo).all() @app.get("/todos/{todo_id}")# 単一のtodoを取得する def read_todos_only(todo_id: int, db: Session = Depends(get_db)): return db.query(Todo).filter(Todo.id == todo_id).first() @app.post("/todos/") # todoを登録する async def create_todo(todo_create: TodoCreate, db: Session = Depends(get_db)): todo = Todo(title=todo_create.title) db.add(todo) db.commit() return db.query(Todo).filter(Todo.id == todo.id).first() @app.put("/todos/{todo_id}") # todoを更新する async def update_todo(todo_id: int, todo_create: TodoCreate, db: Session = Depends(get_db)): todo = db.query(Todo).filter(Todo.id == todo_id).first() todo.title = todo_create.title db.commit() return db.query(Todo).filter(Todo.id == todo_id).first() @app.delete("/todos/{todo_id}") # todoを更新する async def delete_todo(todo_id: int, db: Session = Depends(get_db)): todo = db.query(Todo).filter(Todo.id == todo_id).first(); db.delete(todo) db.commit() if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000)
main.py
ファイルの修正後、docsに入り動作を確認します。
$ python main.py
http://127.0.0.1:8000/docs
を確認するとCRUD機能が反映されていることがわかります。http://127.0.0.1:8000/docs#/default/read_todos_todos__get
下の画像のようにgetコマンドの詳細も確認できました。
curlコマンドで確認すると全データの確認ができました。
curl -X GET "http://127.0.0.1:8000/todos/" -H "accept: application/json" [{"title":"test3","id":3},{"title":"test4","id":4},{"title":"test5","id":5},{"title":"sdfafff","id":6}]%
まとめ
FastAPIに興味があり、せっかくならRDSと接続したいと思い作成しました。いろんな方の作成された記事を読ませてもらいCRUD機能までは作ることができて良かったです。 個人的には、接続時に使用しているsqlalchemyを扱うのも初めてでしたので操作に詰まりましたがpythonからデータベース操作をするにはけっこう使えるという発見もありました。FastAPIは簡易的にAPIを作成できるのでこの記事がどなたかの助けになれば幸いです。