ANTIGRAVITY LABEN
記事一覧/アプリ開発
アプリ開発/2026-03-31初級

Antigravity × Python FastAPI — AI エージェントで RESTful API を高速構築する実践ガイド

Antigravity の AI エージェントを活用して Python FastAPI バックエンドを素早く構築する方法を解説。エンドポイント設計・認証・データベース連携・デプロイまで、実践的なコード例と共に丁寧に説明します。

python26fastapi2backend2rest-apiapp-dev47

取り組みの背景 — Antigravity × Python FastAPI の可能性

Python は世界で最も広く使われているプログラミング言語のひとつであり、バックエンド開発においても人気が高まっています。その中でも FastAPI は、型安全・高パフォーマンス・自動ドキュメント生成という3つの特長から、多くの開発者に選ばれている非同期 Web フレームワークです。

Antigravity の AI エージェントとこの FastAPI を組み合わせると、API の設計から実装・テスト・デプロイまでを驚くほど速く進めることができます。ここではAntigravity を活用して Python FastAPI バックエンドを構築する実践的な手順を、具体的なコード例とともに解説します。

この記事で学べること:

  • Antigravity で Python FastAPI プロジェクトをゼロから立ち上げる方法
  • AI エージェントへの効果的な指示の書き方
  • CRUD エンドポイント・JWT 認証・データベース連携の実装パターン
  • Cloudflare Workers / Railway / Render へのデプロイ手順

対象読者は Python の基礎文法を理解している方で、Antigravity の基本操作(Planning Mode・エージェント起動)を一度でも試したことがある方を想定しています。


環境準備 — Python + FastAPI + Antigravity のセットアップ

必要なツール

開発を始める前に、以下のツールが揃っていることを確認してください。

  • Python 3.11 以上(python --version で確認)
  • pip または uv(高速パッケージマネージャー)
  • Antigravity(最新版)
  • Git

プロジェクトの初期化

まずターミナルで新しいディレクトリを作成し、Antigravity でプロジェクトを開きます。

mkdir my-fastapi-app && cd my-fastapi-app
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate
pip install fastapi uvicorn[standard] sqlmodel pydantic python-jose[cryptography]

Antigravity でプロジェクトを開いたら、まず Planning Mode でプロジェクト全体の構造を設計してもらいましょう。チャットに以下のように入力します:

このディレクトリに Python FastAPI プロジェクトを作成してください。
機能: ユーザー管理 CRUD、JWT 認証、SQLite データベース連携。
ファイル構成も提案してください。

Antigravity のエージェントが以下のようなディレクトリ構造を提案してくれます:

my-fastapi-app/
├── app/
│   ├── __init__.py
│   ├── main.py          # FastAPI アプリのエントリーポイント
│   ├── models.py        # SQLModel / Pydantic モデル定義
│   ├── database.py      # DB 接続・セッション管理
│   ├── auth.py          # JWT 認証ロジック
│   └── routers/
│       ├── users.py     # ユーザー関連エンドポイント
│       └── items.py     # アイテム関連エンドポイント
├── tests/
│   └── test_main.py
├── requirements.txt
└── README.md

CRUD エンドポイントの実装

モデルと DB の定義

Antigravity のエージェントに app/models.pyapp/database.py を生成してもらいます。チャットに指示します:

app/models.py に SQLModel を使ったユーザーモデルを作成してください。
フィールド: id (int, primary key), username (str), email (str), hashed_password (str), created_at (datetime)

生成されたコードは以下のようになります:

# app/models.py
from datetime import datetime
from typing import Optional
from sqlmodel import Field, SQLModel
 
class UserBase(SQLModel):
    username: str = Field(index=True, unique=True)
    email: str = Field(index=True, unique=True)
 
class User(UserBase, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    hashed_password: str
    created_at: datetime = Field(default_factory=datetime.utcnow)
 
class UserCreate(UserBase):
    password: str  # 登録時に受け取る平文パスワード
 
class UserRead(UserBase):
    id: int
    created_at: datetime

続けて app/database.py を生成します:

# app/database.py
from sqlmodel import create_engine, Session, SQLModel
 
DATABASE_URL = "sqlite:///./app.db"
 
engine = create_engine(DATABASE_URL, echo=True)
 
def create_db_and_tables():
    """起動時にテーブルを作成"""
    SQLModel.metadata.create_all(engine)
 
def get_session():
    """FastAPI の Depends で使う DB セッションジェネレーター"""
    with Session(engine) as session:
        yield session

ユーザー CRUD エンドポイント

次に app/routers/users.py を実装します。Antigravity に次のように依頼します:

app/routers/users.py にユーザーの CRUD エンドポイントを作成してください。
GET /users (一覧), GET /users/{id} (詳細), POST /users (作成), DELETE /users/{id} (削除)
パスワードは bcrypt でハッシュ化して保存してください。
# app/routers/users.py
from fastapi import APIRouter, Depends, HTTPException
from sqlmodel import Session, select
from passlib.context import CryptContext
 
from app.database import get_session
from app.models import User, UserCreate, UserRead
 
router = APIRouter(prefix="/users", tags=["users"])
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
 
@router.get("/", response_model=list[UserRead])
def list_users(session: Session = Depends(get_session)):
    """ユーザー一覧を返す"""
    return session.exec(select(User)).all()
 
@router.get("/{user_id}", response_model=UserRead)
def get_user(user_id: int, session: Session = Depends(get_session)):
    """指定 ID のユーザーを返す"""
    user = session.get(User, user_id)
    if not user:
        raise HTTPException(status_code=404, detail="ユーザーが見つかりません")
    return user
 
@router.post("/", response_model=UserRead, status_code=201)
def create_user(user_data: UserCreate, session: Session = Depends(get_session)):
    """新規ユーザーを作成する"""
    hashed_pw = pwd_context.hash(user_data.password)
    user = User(
        username=user_data.username,
        email=user_data.email,
        hashed_password=hashed_pw,
    )
    session.add(user)
    session.commit()
    session.refresh(user)
    return user
 
@router.delete("/{user_id}", status_code=204)
def delete_user(user_id: int, session: Session = Depends(get_session)):
    """指定 ID のユーザーを削除する"""
    user = session.get(User, user_id)
    if not user:
        raise HTTPException(status_code=404, detail="ユーザーが見つかりません")
    session.delete(user)
    session.commit()

JWT 認証の実装

セキュアな API には認証が欠かせません。Antigravity に JWT 認証の実装を依頼しましょう:

app/auth.py に JWT トークンの発行・検証ロジックを実装してください。
ログインエンドポイント POST /auth/token も追加してください。
# app/auth.py
import os
from datetime import datetime, timedelta
from typing import Optional
 
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from sqlmodel import Session, select
 
from app.database import get_session
from app.models import User
 
SECRET_KEY = os.environ.get("SECRET_KEY", "change-this-in-production")
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 60
 
router = APIRouter(prefix="/auth", tags=["auth"])
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/token")
 
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    """JWT アクセストークンを生成する"""
    to_encode = data.copy()
    expire = datetime.utcnow() + (expires_delta or timedelta(minutes=15))
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
 
async def get_current_user(
    token: str = Depends(oauth2_scheme),
    session: Session = Depends(get_session),
) -> User:
    """現在ログイン中のユーザーを取得する"""
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="認証情報が無効です",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception
 
    user = session.exec(select(User).where(User.username == username)).first()
    if user is None:
        raise credentials_exception
    return user
 
@router.post("/token")
def login(
    form_data: OAuth2PasswordRequestForm = Depends(),
    session: Session = Depends(get_session),
):
    """ユーザー名とパスワードで JWT トークンを発行する"""
    user = session.exec(select(User).where(User.username == form_data.username)).first()
    if not user or not pwd_context.verify(form_data.password, user.hashed_password):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="ユーザー名またはパスワードが間違っています",
        )
    token = create_access_token(
        data={"sub": user.username},
        expires_delta=timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES),
    )
    return {"access_token": token, "token_type": "bearer"}

エントリーポイントの統合

最後に app/main.py で各ルーターを登録します:

# app/main.py
from contextlib import asynccontextmanager
from fastapi import FastAPI
 
from app.database import create_db_and_tables
from app.routers import users
from app import auth
 
@asynccontextmanager
async def lifespan(app: FastAPI):
    """起動時に DB テーブルを作成する"""
    create_db_and_tables()
    yield
 
app = FastAPI(
    title="My FastAPI App",
    description="Antigravity × Python FastAPI サンプル",
    version="1.0.0",
    lifespan=lifespan,
)
 
app.include_router(users.router)
app.include_router(auth.router)
 
@app.get("/")
def root():
    return {"message": "Hello, FastAPI + Antigravity!"}

サーバーを起動して確認します:

uvicorn app.main:app --reload
# → http://localhost:8000/docs にアクセスすると自動生成ドキュメントが表示される

期待する出力: INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) と表示され、ブラウザで Swagger UI が確認できます。


Antigravity エージェントを使ったテスト生成

実装が完了したら、Antigravity にテストを自動生成してもらいましょう。チャットに次のように入力します:

tests/test_main.py に pytest + httpx を使ったテストを作成してください。
テスト対象: ユーザー作成・一覧取得・JWT ログイン
# tests/test_main.py
import pytest
from fastapi.testclient import TestClient
from sqlmodel import create_engine, Session, SQLModel
 
from app.main import app
from app.database import get_session
from app.models import User
 
# テスト用インメモリ DB を使用
TEST_DATABASE_URL = "sqlite://"
 
@pytest.fixture(name="session")
def session_fixture():
    engine = create_engine(TEST_DATABASE_URL, connect_args={"check_same_thread": False})
    SQLModel.metadata.create_all(engine)
    with Session(engine) as session:
        yield session
 
@pytest.fixture(name="client")
def client_fixture(session: Session):
    def override_get_session():
        yield session
    app.dependency_overrides[get_session] = override_get_session
    yield TestClient(app)
    app.dependency_overrides.clear()
 
def test_create_user(client: TestClient):
    """ユーザー作成が成功することを確認する"""
    response = client.post("/users/", json={
        "username": "testuser",
        "email": "test@example.com",
        "password": "securepassword123"
    })
    assert response.status_code == 201
    data = response.json()
    assert data["username"] == "testuser"
    assert "hashed_password" not in data  # パスワードが露出しないことを確認
 
def test_login(client: TestClient):
    """JWT トークンの発行が成功することを確認する"""
    # まずユーザーを作成
    client.post("/users/", json={
        "username": "loginuser",
        "email": "login@example.com",
        "password": "password123"
    })
    # ログイン
    response = client.post("/auth/token", data={
        "username": "loginuser",
        "password": "password123"
    })
    assert response.status_code == 200
    assert "access_token" in response.json()

テストを実行します:

pip install pytest httpx
pytest tests/ -v
# 期待する出力: 2 passed in 0.XXs

デプロイ — Railway / Render への公開

Railway でのデプロイ

Railway は Python バックエンドのデプロイが数ステップで完了する便利なプラットフォームです。Antigravity に次のように依頼します:

Railway へのデプロイ用に Procfile と requirements.txt を更新してください。
また、環境変数 SECRET_KEY を安全に扱えるように .env.example も作成してください。

Antigravity が生成するファイル群:

# Procfile
web: uvicorn app.main:app --host 0.0.0.0 --port $PORT

# .env.example
SECRET_KEY=your-secret-key-here
DATABASE_URL=sqlite:///./app.db

デプロイ手順:

# Railway CLI のインストール
npm install -g @railway/cli
 
# ログインとプロジェクト作成
railway login
railway init
 
# 環境変数を設定
railway variables set SECRET_KEY="$(python -c 'import secrets; print(secrets.token_hex(32))')"
 
# デプロイ実行
railway up

セキュアな API バックエンドの構築には、認証・バリデーション・レート制限の実装パターンを詳しく解説した Antigravity エージェントでセキュアな API バックエンドを構築する — 認証・バリデーション・レート制限の実装パターン もぜひご覧ください。


よくあるエラーと対処法

FastAPI + Antigravity の開発でよく遭遇するエラーとその対処法をまとめます。

エラー1: ImportError: No module named 'app'

# NG: ルートから直接実行
python app/main.py
 
# OK: uvicorn でモジュールパスを指定
uvicorn app.main:app --reload

エラー2: sqlalchemy.exc.OperationalError: no such table

lifespan 関数内の create_db_and_tables() が呼ばれているか確認してください。もし @app.on_event("startup") を使っている場合は、FastAPI 0.93 以降では lifespan への移行が推奨されています。

# 旧 (非推奨)
@app.on_event("startup")
def startup():
    create_db_and_tables()
 
# 新 (推奨)
@asynccontextmanager
async def lifespan(app: FastAPI):
    create_db_and_tables()
    yield
 
app = FastAPI(lifespan=lifespan)

エラー3: 422 Unprocessable Entity が返ってくる

リクエストボディの型が一致していない可能性があります。Antigravity に「/docs の Swagger UI を見てエラーの原因を調べてください」と伝えると、自動でバリデーションエラーの詳細を解析してくれます。


まとめ

Antigravity × Python FastAPI の組み合わせは、バックエンド開発の生産性を大きく向上させます。本記事で解説した内容を振り返ります。

  • プロジェクト初期化: Planning Mode でディレクトリ構造を設計し、AI エージェントにひな型を生成してもらう
  • CRUD 実装: SQLModel + FastAPI の組み合わせで型安全な CRUD を素早く実装できる
  • JWT 認証: python-jose + passlib で堅牢な認証フローを AI エージェントが自動構築
  • テスト生成: pytest + httpx のテストコードも Antigravity が自動生成
  • デプロイ: Railway や Render へのデプロイも AI の指示に従うだけ

Python バックエンドを

Antigravity の強みは、コードを書くだけでなく「どう設計するか」というアーキテクチャレベルの提案もしてくれる点にあります。ぜひ今日から Python FastAPI の開発に Antigravity を取り入れてみてください。

シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

アプリ開発2026-07-13
画像の一括最適化をエージェントに任せる前に置く、見た目の劣化を止めるゲート
壁紙アプリの数百枚のアセットをエージェントに一括再エンコードさせたら、数枚だけ色がくすんでいました。サイズ削減率だけでは劣化を見抜けません。SSIM・ΔE・ファイルサイズの3軸でマージ前に不良変換を弾くゲートの設計と、Pillow と scikit-image で動く判定スクリプトをまとめます。
アプリ開発2026-07-09
エージェントが直した .proto がバイナリ互換を壊す前に — buf breaking で wire 互換を門番する
エージェントに .proto を編集させると、テキストとしては正しくても wire 互換を静かに壊すことがあります。フィールド番号の再利用と型変更をどう機械で止めるか、buf breaking と reserved を組み合わせたゲートを動くコードで示します。
アプリ開発2026-07-04
課金済みなのに広告が消えない — StoreKit 2 の Transaction.updates を起動直後に取りこぼす競合を Antigravity と塞いだ記録
起動直後に届く StoreKit 2 のトランザクションを取りこぼす競合を、View 寿命ではなくアプリ寿命にリスナーを固定して塞いだ実装記録。currentEntitlements での照合、finish() の徹底、StoreKitTest での回帰テスト化まで。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →