0
1

More than 1 year has passed since last update.

40代おっさんFastAPI、MongoDB連携メモ①

Last updated at Posted at 2023-01-18

本記事について

この記事はプログラミング初学者の私が学んでいく中でわからない単語や概要を分かりやすくまとめたものです。
もし不正などありましたらコメントにてお知らせいただければ幸いです。

環境ファイルを作る

プロジェクトの直下に.envを作る
次にMongoDBからConnectのパスをコピー
<password>部分を自分で作ったものに変える

MONGO_API_KEY=mongodb+srv://XXXXXXXXXXXXX

次にプロジェクトの直下にdatabase.pyを作る
もう1つschemas.pyを作る

database.py

こちらにはMongoDBと連携する処理を書く

from decouple import config
from typing import Union # 選択肢が2つ以上の場合に使える
import motor.motor_asyncio # こちらでMongoDB連携のために使う

MONGO_API_KEY = config('MONGO_API_KEY') # configを使って環境変数読み込む

client = motor.motor_asyncio.AsyncIOMotorClient(MONGO_API_KEY) # MongoDB連携 APIのキーを渡す
database = client.API_DB # MongoDBの名前と一致
collection_todo = database.todo # MongoDBの名前と一致
collection_user = database.user # MongoDBの名前と一致

## insert_oneを辞書型で返すために必要な関数
def todo_serializer(todo) -> dict:
    return {
        "id": str(todo["_id"]),
        "title": todo["title"],
        "description": todo["description"]
    }

async def db_create_todo(data: dict) -> Union[dict, bool]: # Unionで選択肢をdict, bool選べるようにしている
    todo = await collection_todo.insert_one(data) # insert_oneの返り値 insertResult(インスタンス)返り値になる
    new_todo = await collection_todo.find_one({"_id": todo.inserted_id}) # find_oneでidを取得
    ## find_oneのあるなし判定
    if new_todo:
        return todo_serializer(new_todo) 
    return False
  • insert_oneの返り値 insertResult(インスタンス)返り値になる。insert_idと言う属性が付与され、追加したIDを取得される。
  • insert_oneで返されたinsertResult(インスタンス)はオブジェクトクラスから生成されたインスタンスなので単純なstring型にならない(タイムスタンプなど色々入っている)
  • find_oneでidを取得 _idで格納されている。
  • find_oneのリターンのタイプは
    • ある場合はドキュメントを返して
    • 無い場合はnoneを返す

schemas.py

エンドポイントに渡すデータ型
レスポンスのデータ型を定義する。

from pydantic import BaseModel # 型を定義するために使う

# エンドポイント返すデータ型
class Todo(BaseModel):
    id: str
    title: str
    description: str

# 新規作成に渡すデータ型
class TodoBody(BaseModel):
    title: str
    description: str

# mainのrootのデータ型
class SuccessMsg(BaseModel):
    message: str

route_todo.py

エンドポイントを作る

from fastapi import APIRouter # routerを作るのに必要
from fastapi import Response, Request, HTTPException # 11行目、21行目の関数
from fastapi.encoders import jsonable_encoder # jsonable_encoder型で受け取ったデータを辞書型にするために必要
from schemas import Todo, TodoBody # 型定義
from database import db_create_todo # database.pyで作った関数
from starlette.status import HTTP_201_CREATED # ステータスコードを上書きするのに必要

router = APIRouter() # インスタンス化

@router.post("/api/todo", response_model=Todo)
async def create_todo(request: Request, response: Response, data:TodoBody): # 実行されたときの関数を定義
    todo = jsonable_encoder(data) # 受け取ったdataを辞書型にする
    res = await db_create_todo(todo)
    response.status_code = HTTP_201_CREATED # ステータスコードの上書き
    # jsonable_encoder型存在していたらデータを存在しなければnoneを返すので判定する
    if res:
        return res
    # db_create_todoでFalseの場合の例外処理
    raise HTTPException(
        status_code=404, detail="Create task failed"
    )

main.py

from fastapi import FastAPI
from routers import route_todo # 作ったroutersのroute_todo
from schemas import SuccessMsg

app = FastAPI()
app.include_router(route_todo.router) # appにルートを追加

@app.get("/", response_model=SuccessMsg)
def root():
    return {"message": "利樹大好きだよ~~ん"}

参考

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1