[備忘録]カテゴリを操作するAPIをFlaskで作る

## 目的
この章ではフロントエンド(JS)と連携できるように、カテゴリの一覧取得・追加・編集・削除ができる**RESTful API**をFlaskで実装する。
最終的には以下のようなエンドポイントを持つAPIを構築する。

| メソッド | パス | 内容 |
|:-:|:-:|:-:|
| GEt  | `api/categories`  |  カテゴリー一覧取得 |
| POST  | `api/categories`  |  新規カテゴリ追加 |
|  PUT | `api/categories/<id>`  |  指定カテゴリ編集 |
|  DELETE | `api/categories/<id>`  | 指定カテゴリ削除  |

~~~:フォルダ構成
app/
└── routes/
    └── category.py  ← この章で作成！
~~~

## 1.BlueprintによるAPIルートを作成
ファイル: `app/routes/category.py`
~~~python:app/routes/categories.py
from flask import Blueprint, request, jsonify
from app.db import db
from app.models.budget import Category

category_bp = Blueprint("category_bp", __name__, url_prefix="/api/categories")

~~~

### Create処理
~~~python
# カテゴリ新規作成
@category_bp.route("", methods=["POST"])
def create_category():
    data = request.json
    name = data.get("name")
    expense_type = data.get("expense_type")

    if not name or expense_type not in ["expense", "income"]:
        return jsonify({"error": "Invalid data"}), 400

    category = Category(name=name, expense_type=expense_type)
    db.session.add(category)
    db.session.commit()
    return jsonify({"message": "Category created", "id": category.id}), 201
~~~
- `request.json`で送られてきたデータ(`name`, `expense_type`)を取得
- `Category`モデルをインスタンス化し、DBに追加・保存(`commit()`)
- 成功時にステータス201とともにメッセージを返す

### Read処理
- DBから全カテゴリを取得(`Category.query.all()`)
- JSON形式で整形して返す
~~~python
# カテゴリ一覧取得
@category_bp.route("", methods=["GET"])
def get_categories():
    categories = Category.query.all()
    return jsonify([
        {
            "id": c.id,
            "name": c.name,
            "expense_type": c.expense_type
        } for c in categories
    ]), 200
~~~

### Update処理
~~~python
# カテゴリの更新
@category_bp.route("/<int:category_id>", methods=["PUT"])
def update_category(category_id):
    category = Category.query.get(category_id)
    if not category:
        return jsonify({"error": "Category not found"}), 404

    data = request.json
    category.name = data.get("name", category.name)
    category.expense_type = data.get("expense_type", category.expense_type)

    db.session.commit()
    return jsonify({"message": "Category updated"}), 200
~~~
- URLの`</id>`から対象のカテゴリを取得
- 新しい値が送られていれば更新
- `commit()`して保存

### Delete処理
- 指定されたIDのカテゴリを取得
- 存在すれば削除(`db.session.delete()`)
- `commit()`して反映
~~~python
# カテゴリの削除
@category_bp.route("/<int:category_id>", methods=["DELETE"])
def delete_category(category_id):
    category = Category.query.get(category_id)
    if not category:
        return jsonify({"error": "Category not found"}), 404

    db.session.delete(category)
    db.session.commit()
    return jsonify({"message": "Category deleted"}), 200
~~~

## 2.Flaksアプリにルートを登録する
ファイル：`app/__init__.py`に追記
~~~py:app/__init__.py
from app.routes.category import category_bp
app.register_blueprint(category_bp)
~~~


## 3.動作確認(curlから)
### curlとは → コマンドラインでAPIをテストできるツール
`curl`(カール)は、ターミナルやコマンドプロンプトから**HTTPリクエストを送ることができるツール**です。
例えば「GETで一覧を取得」「POST」で新規登録などを、ブラウザを使わずに直接送ることができます。

### APIサーバーを起動する：`run.py`の作成
curlコマンドでAPIにアクセスするには、Flaskアプリを実行しておく必要があります。そのための起動スクリプト`run.py`をプロジェクトルートに作成します。
~~~:フォルダ構成
js_db_crud/
├── run.py             ← ここからFlaskアプリを起動
├── app/
~~~
~~~py:run.py
from app import create_app

app = create_app()

if __name__ == "__main__":
    app.run(debug=True)
~~~

### APIサーバーを起動する：サーバーの起動
ターミナルでプロジェクトのルートディレクトリに移動し、以下を実行します：
~~~:bash
python run.py
~~~
成功すると、以下のようなログが出てAPIサーバーが立ち上がります：
~~~
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
~~~

### curlでアクセス
まず、サーバーを立ち上げているのとは別のターミナルを
開いてください。
次に、`GET`で現在のカテゴリー一覧を取得して`id`を確認：
~~~:bash
curl http://localhost:5000/api/categories
~~~
例えば、こんなレスポンスが返ってきたら
~~~json
[
  {
    "id": 1,
    "name": "食費",
    "expense_type": "expense"
  },
  {
    "id": 2,
    "name": "給料",
    "expense_type": "income"
  }
]
~~~
この`id`を使って`PUT`や`DELETE`を実行する。

### POST(新規作成)
~~~:bash
curl -X POST http://localhost:5000/api/categories -H "Content-Type: application/json" -d "{\"name\": \"光熱費\", \"expense_type\": \"expense\"}"
~~~

### PUT(編集)
カテゴリ`id=1`(例えば「食費」)の名前を「食料品」に変更する場合：
~~~:bash
curl -X PUT http://localhost:5000/api/categories/1 -H "Content-Type: application/json" -d "{\"name\": \"食料品\", \"expense_type\": \"expense\"}"
~~~

### DELETE(削除)
カテゴリー`id=1`を削除したい場合：
~~~:bash
curl -X DELETE http://localhost:5000/api/categories/1
~~~

## この章のまとめ
- `Blueprint`によるAPIルーティング
- 各エンドポイントで`CRUD`処理を実装
- APIサーバー起動用の`run.py`を作成
- `curl`を使ってAPIを叩き、DBのレコード操作ができることを検証

次章では、今回作成したカテゴリAPIを**JavaScriptから呼び出し、ブラウザ上でカテゴリを操作できるUI**を実装していきます。