13
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

こんにちは、いのせです。
今回は、研修チーム開発で用いたFastAPIをハンズオン形式で学べるように初学者向けに書いてみました。

FastAPIは、Pythonで簡単にWeb APIを作ることができるフレームワークです。
このハンズオンでは、基本的なところから、ステップバイステップで学んでいきます。

FastAPIとは

FastAPIは、Pythonで高速かつ簡単にWeb APIを構築するためのモダンなフレームワークです。非同期処理をサポートし、StarletteとPydanticを基盤にしているため、高パフォーマンスで型安全なAPI開発が可能です。自動生成されるOpenAPIドキュメント(Swagger UI)により、APIのテストやドキュメント化が容易です。主に、効率的でスケーラブルなWebアプリケーションやマイクロサービスの構築に使用されます。

image.png

今回作るもの

シンプルな本の管理APIを作ります。
本を追加したり、一覧を見たり、削除したりできるAPIです。

image.png

事前準備

必要なもの

  • Python 3.7以上
  • テキストエディタ(メモ帳でもOK、VS Codeがおすすめ)

インストール

# ターミナル(コマンドプロンプト)で実行
pip install fastapi uvicorn

Step 1: 一番シンプルなAPI - Hello World

ファイルを作成

main.py というファイルを作って、以下を書いてください:

from fastapi import FastAPI

# FastAPIアプリを作成
app = FastAPI()

@app.get("/")
def hello():
    return {"message": "Hello World!"}

🔍 FastAPI特有の機能解説

FastAPI() とは?

app = FastAPI()
  • これがFastAPIアプリケーションの「土台」を作る命令です
  • app という名前で、APIの機能をまとめる箱を作ったと思ってください

@app.get("/") とは?

@app.get("/")
def hello():
    return {"message": "Hello World!"}
  • @app.get は「GETリクエストを受け取る」という意味のデコレータです
  • "/" は URL のパス(アドレス)です
  • つまり「トップページ(/)にGETリクエストが来たら、hello関数を実行して」という意味

戻り値について

return {"message": "Hello World!"}
  • FastAPIでは、辞書(dict)を返すと自動的にJSON形式に変換されます
  • つまり {"message": "Hello World!"} が JSON として返されます

実行してみよう

uvicorn main:app --reload

ブラウザで http://127.0.0.1:8000 にアクセスしてみてください。

Step 2: データを扱う - Pydanticモデル

本のデータ構造を定義

main.py を以下のように書き換えてください:

from fastapi import FastAPI
from pydantic import BaseModel

# FastAPIアプリを作成
app = FastAPI()

# 本のデータ構造を定義
class Book(BaseModel):
    title: str        # タイトル(文字列)
    author: str       # 著者(文字列)
    pages: int        # ページ数(整数)
    published: bool   # 出版済みかどうか(True/False)

@app.get("/")
def hello():
    return {"message": "本の管理APIです"}

🔍 Pydantic特有の機能解説

BaseModel とは?

from pydantic import BaseModel

class Book(BaseModel):
    title: str
    author: str
    pages: int
    published: bool
  • BaseModel は、データの「型」を定義するためのクラスです
  • title: str は「titleは文字列(string)型」という意味
  • pages: int は「pagesは整数(integer)型」という意味
  • published: bool は「publishedは真偽値(boolean)型」という意味

なぜこれが重要?

  • 自動バリデーション: 間違った型のデータが来ると、自動的にエラーになります
  • 自動文書化: API文書に、どんなデータが必要かが自動で表示されます
  • エディタサポート: VS Codeなどで、入力補完が効きます

Step 3: データを保存する場所を作る

メモリ上にデータを保存

main.py に以下を追加:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Book(BaseModel):
    title: str
    author: str
    pages: int
    published: bool

# 本のデータを保存するリスト(本来はデータベースを使います)
books = []

@app.get("/")
def hello():
    return {"message": "本の管理APIです"}

# 本の一覧を取得
@app.get("/books")
def get_books():
    return books

🔍 リストとエンドポイントの解説

グローバル変数 books

books = []
  • 本のデータを保存するための空のリストです
  • 本来はデータベースを使いますが、今回は学習のためリストを使います
  • プログラムを再起動すると、データは消えてしまいます

新しいエンドポイント

@app.get("/books")
def get_books():
    return books
  • /books というURLで本の一覧を取得できます
  • 最初は空のリスト [] が返されます

実行して確認

http://127.0.0.1:8000/books にアクセスしてみてください。空のリスト [] が表示されるはずです。

Step 4: 本を追加する機能

POSTエンドポイントを追加

main.py に以下を追加:

@app.post("/books")
def add_book(book: Book):
    books.append(book)
    return {"message": "本を追加しました", "book": book}

🔍 POSTエンドポイントの解説

@app.post とは?

@app.post("/books")
def add_book(book: Book):
  • @app.post は「POSTリクエストを受け取る」という意味
  • GETは「データを取得」、POSTは「データを送信・作成」に使います

引数 book: Book とは?

def add_book(book: Book):
  • book という名前の引数を受け取ります
  • Book 型なので、Bookクラスの形式でデータが送られてきます
  • FastAPIが自動的にJSONをBookオブジェクトに変換してくれます

リストへの追加

books.append(book)
  • 受け取った本のデータを、books リストに追加します

テストしてみよう

  1. http://127.0.0.1:8000/docs にアクセス

  2. POST /books をクリック

  3. 「Try it out」をクリック

    4-1.png

  4. 以下のような JSON を入力:

    {
      "title": "Python入門",
      "author": "田中太郎",
      "pages": 300,
      "published": true
    }
    
  5. 「Execute」をクリック

    4-2.png

そして http://127.0.0.1:8000/books で本が追加されているか確認してみてください!

Step 5: 特定の本を取得する

パスパラメータを使う

main.py に以下を追加:

@app.get("/books/{book_id}")
def get_book(book_id: int):
    if book_id < len(books):
        return books[book_id]
    return {"error": "本が見つかりません"}

🔍 パスパラメータの解説

{book_id} とは?

@app.get("/books/{book_id}")
def get_book(book_id: int):
  • URLの一部を変数として受け取ることができます
  • 例:/books/0 なら book_id は 0
  • 例:/books/1 なら book_id は 1
  • book_id: int と書くことで、整数のみ受け付けるようになります

リストのインデックス

if book_id < len(books):
    return books[book_id]
  • len(books) はリストの長さ(要素数)
  • books[0] は最初の本、books[1] は2番目の本
  • 存在しないインデックスの場合は、エラーメッセージを返します

テストしてみよう

  1. 先ほど本を1冊追加していれば、http://127.0.0.1:8000/books/0 にアクセス
  2. その本の情報が表示されるはず
  3. http://127.0.0.1:8000/books/999 にアクセスして、エラーメッセージも確認

Step 6: 本を削除する機能

DELETEエンドポイントを追加

main.py に以下を追加:

@app.delete("/books/{book_id}")
def delete_book(book_id: int):
    if book_id < len(books):
        deleted_book = books.pop(book_id)
        return {"message": "本を削除しました", "deleted_book": deleted_book}
    return {"error": "本が見つかりません"}

🔍 DELETEエンドポイントの解説

@app.delete とは?

@app.delete("/books/{book_id}")
  • DELETEは「データを削除」する時に使うHTTPメソッドです
  • GET(取得)、POST(作成)、DELETE(削除)が基本的な操作です

pop() メソッド

deleted_book = books.pop(book_id)
  • pop(book_id) は、指定したインデックスの要素を削除して、その要素を返すメソッドです
  • 削除された本の情報も返すので、ユーザーに「何を削除したか」を教えることができます

Step 7: エラーハンドリングを改善

HTTPExceptionを使う

main.py の先頭に追加:

from fastapi import FastAPI, HTTPException

そして、エラー処理を以下のように変更:

@app.get("/books/{book_id}")
def get_book(book_id: int):
    if book_id < 0 or book_id >= len(books):
        raise HTTPException(status_code=404, detail="本が見つかりません")
    return books[book_id]

@app.delete("/books/{book_id}")
def delete_book(book_id: int):
    if book_id < 0 or book_id >= len(books):
        raise HTTPException(status_code=404, detail="本が見つかりません")
    deleted_book = books.pop(book_id)
    return {"message": "本を削除しました", "deleted_book": deleted_book}

🔍 HTTPExceptionの解説

HTTPException とは?

from fastapi import FastAPI, HTTPException

raise HTTPException(status_code=404, detail="本が見つかりません")
  • 適切なHTTPステータスコードでエラーを返すためのクラスです
  • status_code=404 は「Not Found(見つからない)」という意味
  • detail はエラーの詳細メッセージです

なぜ raise を使う?

  • return でエラーを返すと、ステータスコードは200(成功)になってしまいます
  • raise HTTPException を使うと、適切なエラーステータスコードが返されます
  • APIを使う側(フロントエンドなど)が、成功かエラーかを正しく判断できます

Step 8: 完成したコード全体

最終的な main.py

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

# FastAPIアプリを作成
app = FastAPI(title="本の管理API", description="初心者向けの本管理システム")

# 本のデータ構造を定義
class Book(BaseModel):
    title: str        # タイトル
    author: str       # 著者
    pages: int        # ページ数
    published: bool   # 出版済みかどうか

# 本のデータを保存するリスト
books = []

@app.get("/")
def hello():
    """APIの基本情報"""
    return {
        "message": "本の管理APIです", 
        "endpoints": {
            "本の一覧": "GET /books",
            "本の追加": "POST /books", 
            "特定の本": "GET /books/{id}",
            "本の削除": "DELETE /books/{id}"
        }
    }

@app.get("/books")
def get_books():
    """すべての本を取得"""
    return {"books": books, "count": len(books)}

@app.post("/books")
def add_book(book: Book):
    """新しい本を追加"""
    books.append(book)
    return {
        "message": "本を追加しました", 
        "book": book, 
        "total_books": len(books)
    }

@app.get("/books/{book_id}")
def get_book(book_id: int):
    """特定の本を取得"""
    if book_id < 0 or book_id >= len(books):
        raise HTTPException(status_code=404, detail="本が見つかりません")
    return books[book_id]

@app.delete("/books/{book_id}")
def delete_book(book_id: int):
    """本を削除"""
    if book_id < 0 or book_id >= len(books):
        raise HTTPException(status_code=404, detail="本が見つかりません")
    
    deleted_book = books.pop(book_id)
    return {
        "message": "本を削除しました", 
        "deleted_book": deleted_book,
        "remaining_books": len(books)
    }

実行方法

uvicorn main:app --reload

使い方

  1. API文書を見る: http://127.0.0.1:8000/docs
  2. 基本情報: http://127.0.0.1:8000/
  3. 本の一覧: http://127.0.0.1:8000/books

最後に

今回はFastAPI初学者でもわかるようにハンズオン形式で本の管理APIの開発を行いました。
これよりももっと発展させていきたい場合は、公式ドキュメントなどを読んで開発をしてみてください!

チュートリアルもおすすめです。

13
6
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
13
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?