APIの仕組みを理解する（自分用）

はじめに
-
本記事は、APIの仕組みを自分の手で実装しながら理解することを目的としています。
主に以下の技術を使いながら、FastAPIとStreamlitの連携についてまとめる。

<strong>FastAPI（エンドポイントの構築）
Streamlit（UIの構築とデータの表示）
JSONファイル（データの保存と表示）</strong>

ディレクトリ構造と各ファイルの内容
-
```
sample/
├── main.py         # streamlitでのUI構築
├── test_api.py      # fastapiによるAPIエンドポイント
├── module.py       # 処理用関数やモデルの定義
├── sample.json     # APIで読み書きするJSONファイル
```

```python:main.py
import module
import streamlit as st

URL = "http://localhost:8000/"
FILE_PATH="sample.json"

# StreamlitのUI
st.title("データ登録とAPIの呼び出し")

if st.button(label="APIからデータ取得する"):
    res = module.request_json(URL)
    if isinstance(res, dict) and "error" in res:
        st.error(res["error"])  # エラーメッセージをStreamlitで表示
    else:
        for item in res:
            for index in item.items():
                st.write(index)
                
col_1,col_2=st.columns(2)
with col_1:
    name = st.text_input("名前")
with col_2:
    age = st.number_input("年齢", min_value=0, step=1)

if st.button("APIへデータを追加する"):
    file_path = FILE_PATH  
    reg = module.Registration(file_path=file_path, name=name, age=int(age))
    module.regist_data(reg)
    
```
```python:test_api.py
from fastapi import FastAPI
import json

app=FastAPI()

RESPONSE_JSON="sample.json"

@app.get("/")
async def response_json():
  with open(RESPONSE_JSON,"r",encoding="utf-8") as f:
    data=json.load(f)
    
    return data
    
```
```python:module.py
import requests
from dataclasses import dataclass
import os
import json
import streamlit as st

@dataclass
class Registration:
    file_path: str | int
    name: str
    age: int

def request_json(url):
    try:
        response = requests.get(url, timeout=5)
        response.raise_for_status()  # HTTPエラー時に例外発生
        return response.json()
    except requests.exceptions.HTTPError as e:
        return {"error": f"HTTPエラー: {e.response.status_code}"}
    except requests.exceptions.ConnectionError:
        return {"error": "サーバーに接続できません"}
    except requests.exceptions.Timeout:
        return {"error": "タイムアウトしました"}
    except Exception as e:
        return {"error": f"予期しないエラー: {str(e)}"}
    
def regist_data(registration: Registration):
    # JSONファイルの読み込みまたは新規作成
    file_path = str(registration.file_path)
    data = []
    if os.path.exists(file_path):
        with open(file_path, "r", encoding="utf-8") as f:
            try:
                data = json.load(f)
            except json.JSONDecodeError:
                data = []
    # 新しいデータを追加
    data.append({"name": registration.name, "age": registration.age})
    # ファイルに書き込み
    with open(file_path, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)
    st.write(f"登録完了しました。, 名前={registration.name}, 年齢={registration.age}")
    
```
```json:sample.json
[
  {
    "name": "Alice",
    "age": 28
  },
  {
    "name": "Bob",
    "age": 34
  },
  {
    "name": "Charlie",
    "age": 22
  }
]
```
 uvicornでFastAPIの起動方法
-
testapi.py内でFastAPIアプリをapp = FastAPI()として定義していることが前提です。
```bash:bash
uvicorn testapi:app --reload
```

Streamlitの起動と基本構成
-
StreamlitのUIからエンドポイントにアクセスし、データを取得・表示する流れを構築します。
```bash:bash
streamlit run main.py
```

APIエンドポイントへアクセスしてデータを取得・描画
-
Streamlitアプリ上で、FastAPIのエンドポイントにリクエストを送り、JSON形式でレスポンスを受け取り、画面に表示します。
（下記のように、ブラウザからエンドポイントへ直接アクセスすることも可能）
```URL:URL（エンドポイント）
http://localhost:8000/

# 結果
[{"name":"Alice","age":28},{"name":"Bob","age":34},{"name":"Charlie","age":22}]
```

APIの仕組みに関する総括
-
FastAPIは軽量かつ直感的にAPIエンドポイントを構築できる
StreamlitはUIの構築に強く、データ表示や操作を素早く実装できる
JSONファイルを簡易的なDBとして扱うことで、API入門には十分な学習素材になる

おわりに
-
この記事は、APIを「なんとなく使う」から「仕組みを理解して活用する」ための足がかりとしてまとめました。
これからもっと複雑なアプリケーションに挑戦していきたい方の参考になれば幸いです。