初心者でも作れる独自API開発|DB設計・API設計・エンドポイント公開までの全手順

データベース

「外部サービスに依存せず、自分だけのAPIを持ちたい」「スクレイピングで集めたデータや自社データをAPIとして配信したい」

そんなニーズに応えるのが独自API(自作REST API)の構築です。データ収集・データベース設計・APIサーバー構築・公開までの一連の流れを、実践的なサンプルコードとともに解説します。


1. 独自APIとは?作るメリット

独自APIとは、自分でサーバーを用意し、自分のデータを好きな形式・好きなエンドポイントで提供できる仕組みです。

比較項目 既存の外部API 独自API
データの自由度 提供されたものだけ 自分で設計できる
料金 従量課金が多い サーバー代のみ
レート制限 あり(厳しい場合も) 自分でコントロール
データ鮮度 提供側に依存 自分で更新タイミングを決定
カスタマイズ 不可 自由自在

2. 全体アーキテクチャ

今回構築するシステムの全体像は以下の通りです。

レイヤー 役割 技術スタック例
データ収集 スクレイピング・外部APIなどでデータを集める Python / requests / Playwright
データベース 収集データを永続化・管理 SQLite / PostgreSQL / MySQL
APIサーバー DBのデータをJSON形式で配信 FastAPI / Flask / Express
公開・運用 外部からアクセスできるよう公開 Render / Railway / VPS / AWS

データの流れはシンプルです:データ収集 → DB保存 → APIで提供。この3ステップを順番に実装していきましょう。


3. データベースを設計・構築する

3-1. どのDBを選ぶか

DB おすすめ用途 特徴
SQLite 小規模・個人開発・ローカル検証 ファイル1つで動く。導入ゼロ
PostgreSQL 本番運用・複雑なクエリ 高機能・JSON型対応・無料で使える
MySQL Webアプリとの相性重視 普及率が高く情報が豊富

まずは SQLite で手軽に始め、規模が大きくなったら PostgreSQL へ移行するのが王道です。

3-2. テーブル設計サンプル(商品情報の場合)

-- 商品テーブル
CREATE TABLE products (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    name        TEXT    NOT NULL,
    price       INTEGER NOT NULL,
    category    TEXT,
    source_url  TEXT,
    created_at  DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at  DATETIME DEFAULT CURRENT_TIMESTAMP
);

-- カテゴリマスタ
CREATE TABLE categories (
    id   INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT UNIQUE NOT NULL
);

3-3. Pythonでデータを投入する

import sqlite3
from datetime import datetime

# DB接続
conn = sqlite3.connect("myapi.db")
cursor = conn.cursor()

# データ挿入
def insert_product(name, price, category, source_url):
    cursor.execute("""
        INSERT INTO products (name, price, category, source_url, updated_at)
        VALUES (?, ?, ?, ?, ?)
    """, (name, price, category, source_url, datetime.now()))
    conn.commit()

# 呼び出し例
insert_product("ワイヤレスイヤホン", 4980, "家電", "https://example.com/item/123")
insert_product("メカニカルキーボード", 12800, "PC周辺機器", "https://example.com/item/456")

conn.close()

4. FastAPIでREST APIを作る

Python製フレームワークの FastAPI は、自動でSwagger UIを生成してくれる・型ヒントで安全に書ける・処理が速いという三拍子揃った、独自API構築の最有力候補です。

4-1. インストール

pip install fastapi uvicorn

4-2. 基本的なAPIサーバーの実装

from fastapi import FastAPI, HTTPException, Query
from pydantic import BaseModel
import sqlite3
from typing import Optional, List

app = FastAPI(title="MyProduct API", version="1.0.0")

# DB接続ヘルパー
def get_db():
    conn = sqlite3.connect("myapi.db")
    conn.row_factory = sqlite3.Row  # 辞書形式で取得
    return conn

# レスポンスの型定義
class Product(BaseModel):
    id: int
    name: str
    price: int
    category: Optional[str]
    source_url: Optional[str]
    created_at: str

# ---- エンドポイント ----

# 全件取得
@app.get("/products", response_model=List[Product])
def get_products(
    category: Optional[str] = Query(None, description="カテゴリで絞り込み"),
    limit: int = Query(20, le=100, description="取得件数(最大100)"),
    offset: int = Query(0, description="オフセット")
):
    conn = get_db()
    query = "SELECT * FROM products WHERE 1=1"
    params = []

    if category:
        query += " AND category = ?"
        params.append(category)

    query += " LIMIT ? OFFSET ?"
    params.extend([limit, offset])

    rows = conn.execute(query, params).fetchall()
    conn.close()
    return [dict(row) for row in rows]

# 1件取得
@app.get("/products/{product_id}", response_model=Product)
def get_product(product_id: int):
    conn = get_db()
    row = conn.execute(
        "SELECT * FROM products WHERE id = ?", (product_id,)
    ).fetchone()
    conn.close()

    if row is None:
        raise HTTPException(status_code=404, detail="Product not found")
    return dict(row)

# 検索
@app.get("/products/search/", response_model=List[Product])
def search_products(q: str = Query(..., description="商品名で検索")):
    conn = get_db()
    rows = conn.execute(
        "SELECT * FROM products WHERE name LIKE ?", (f"%{q}%",)
    ).fetchall()
    conn.close()
    return [dict(row) for row in rows]

4-3. サーバーを起動する

# 開発時(ホットリロードあり)
uvicorn main:app --reload

# 本番時
uvicorn main:app --host 0.0.0.0 --port 8000

起動後、http://localhost:8000/docs にアクセスすると、Swagger UI(自動生成されたAPIドキュメント)が表示されます。ブラウザ上で実際にAPIをテストすることも可能です。


5. APIエンドポイント一覧を整理する

実装したAPIのエンドポイントを整理すると以下のようになります。

メソッド エンドポイント 説明 クエリパラメータ
GET /products 商品一覧を取得 category, limit, offset
GET /products/{id} 商品を1件取得 なし
GET /products/search/ 商品名で検索 q(検索ワード)

5-1. レスポンス例

// GET /products?category=家電&limit=2 のレスポンス
[
  {
    "id": 1,
    "name": "ワイヤレスイヤホン",
    "price": 4980,
    "category": "家電",
    "source_url": "https://example.com/item/123",
    "created_at": "2025-03-16 10:00:00"
  },
  {
    "id": 3,
    "name": "スマートスピーカー",
    "price": 8800,
    "category": "家電",
    "source_url": "https://example.com/item/789",
    "created_at": "2025-03-16 10:05:00"
  }
]

6. データを自動更新する仕組みを作る

APIのデータを常に最新に保つには、定期実行の仕組みが必要です。

6-1. APSchedulerで定期実行(Python内)

from apscheduler.schedulers.background import BackgroundScheduler
import requests
from bs4 import BeautifulSoup

def collect_and_update():
    """データを収集してDBを更新する処理"""
    print("データ更新開始...")
    # ここに収集ロジックを書く
    # insert_product(...) を呼び出してDBを更新
    print("データ更新完了")

# FastAPI起動時にスケジューラーも起動
scheduler = BackgroundScheduler()
scheduler.add_job(collect_and_update, "interval", hours=6)  # 6時間ごと
scheduler.start()

6-2. cronで定期実行(サーバー)

# crontab -e で編集
# 毎日午前3時に更新スクリプトを実行
0 3 * * * /usr/bin/python3 /home/user/myapi/collect.py >> /var/log/collect.log 2>&1

6-3. GitHub Actionsで定期実行(クラウド)

# .github/workflows/update_data.yml
name: Update API Data

on:
  schedule:
    - cron: "0 */6 * * *"  # 6時間ごと

jobs:
  update:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: "3.11"
      - name: Install dependencies
        run: pip install -r requirements.txt
      - name: Run data collector
        run: python collect.py

7. APIを外部公開する

7-1. ホスティングサービスの比較

サービス 無料枠 特徴 おすすめ度
Render あり(スリープあり) Dockerも使える・設定が簡単 ★★★★★
Railway あり(月500時間) DBも一緒にデプロイしやすい ★★★★☆
Fly.io あり(小規模) エッジ配信・高速 ★★★★☆
VPS(ConoHa等) なし(月数百円〜) 自由度最高・本番向け ★★★★☆
AWS Lambda あり(100万回/月) サーバーレス・スケーラブル ★★★☆☆(複雑)

7-2. Renderへのデプロイ手順

# 1. requirements.txt を作成
pip freeze > requirements.txt

# 2. Procfile を作成(Renderが読むファイル)
echo "web: uvicorn main:app --host 0.0.0.0 --port $PORT" > Procfile

# 3. GitHubにpush
git init
git add .
git commit -m "first commit"
git remote add origin https://github.com/yourname/myapi.git
git push -u origin main

# あとはRenderのダッシュボードでリポジトリを連携するだけ!

8. セキュリティ対策を忘れずに

公開APIには最低限のセキュリティ対策が必要です。

8-1. APIキー認証を追加する

from fastapi import Header, HTTPException
import os

API_KEY = os.environ.get("API_KEY", "your-secret-key")

def verify_api_key(x_api_key: str = Header(...)):
    if x_api_key != API_KEY:
        raise HTTPException(status_code=403, detail="Invalid API Key")

# エンドポイントに認証を追加
@app.get("/products", dependencies=[Depends(verify_api_key)])
def get_products():
    ...

8-2. レート制限を設ける

pip install slowapi
from slowapi import Limiter
from slowapi.util import get_remote_address

limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter

@app.get("/products")
@limiter.limit("30/minute")  # 1分間に30回まで
def get_products(request: Request):
    ...

8-3. セキュリティチェックリスト

対策 方法 優先度
APIキー認証 Headerで検証
レート制限 slowapi / nginx
HTTPS化 Let’s Encrypt / Renderなら自動
SQLインジェクション対策 プレースホルダー(?)を使う
CORS設定 fastapi.middleware.cors
ログ監視 アクセスログの定期確認

9. まとめ|独自API構築のロードマップ

独自APIを作る流れを改めて整理します。

  1. データを集める:スクレイピング・外部API・手動入力など手段は問わない
  2. DBに保存する:まずはSQLiteで十分。テーブル設計を丁寧に
  3. FastAPIでエンドポイントを作る:GET系から始めてPOST/PUT/DELETEへ拡張
  4. 定期更新の仕組みを入れる:cronやGitHub Actionsで自動化
  5. 外部公開する:RenderやRailwayで手軽に公開
  6. セキュリティを固める:APIキー・レート制限・HTTPSは必須

最初は小さく始めて、少しずつ機能を拡張していくのがコツです。自分だけのAPIは、個人開発・副業・ポートフォリオとして非常に強力な武器になります。ぜひ挑戦してみてください。

コメント

タイトルとURLをコピーしました