「外部サービスに依存せず、自分だけの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を作る流れを改めて整理します。
- データを集める:スクレイピング・外部API・手動入力など手段は問わない
- DBに保存する:まずはSQLiteで十分。テーブル設計を丁寧に
- FastAPIでエンドポイントを作る:GET系から始めてPOST/PUT/DELETEへ拡張
- 定期更新の仕組みを入れる:cronやGitHub Actionsで自動化
- 外部公開する:RenderやRailwayで手軽に公開
- セキュリティを固める:APIキー・レート制限・HTTPSは必須
最初は小さく始めて、少しずつ機能を拡張していくのがコツです。自分だけのAPIは、個人開発・副業・ポートフォリオとして非常に強力な武器になります。ぜひ挑戦してみてください。


コメント