03. API 契約と認証 03. API contract & auth

BFF だけを叩く。OpenAPI は openapi-app-mobile.json Talk only to the BFF. OpenAPI lives at openapi-app-mobile.json.

モバイルは Parky BFF(/v1/*)のみを叩きます。Supabase の DB を直接叩いたり、 Supabase Edge Functions を叩いたりはしません。認証トークンの取得だけは Supabase Auth を直接使います。

The mobile app talks only to the Parky BFF (/v1/*) — never to Supabase DB or Edge Functions. The one exception is Supabase Auth, which is used directly to obtain / refresh JWTs.

OpenAPI — 読むべきはこの 1 ファイル OpenAPI — this one file is enough

役割Role ファイルFile ビューアViewer
モバイル用(読むのはこれ) Mobile (read this) openapi-app-mobile.json (paths 83) Swagger UIRedoc
全チャネル統合版(参考) Unified spec (for reference) openapi.json (paths 367) Swagger UIRedoc
Servers(OpenAPI から読み込まれる環境): https://dev-api.parky.co.jp(dev)/ https://api.parky.co.jp(prod)/ http://localhost:8787(ローカル)。 Swagger UI の Try-it は常に dev に向きます(本番の誤発火防止)。 Servers declared in OpenAPI: https://dev-api.parky.co.jp (dev), https://api.parky.co.jp (prod), and http://localhost:8787 (local). Swagger UI's Try it out is pinned to dev (guards against accidental prod calls).

認証フロー(完結版) Authentication flow (end-to-end)

Parky は Supabase Auth によるメール + パスワード認証を採用します。 モバイル側は supabase_flutter SDK でトークン取得/更新のみ行い、 API 呼び出しには取得した JWT を Authorization: Bearer ヘッダに載せて Parky BFF に送ります。

Parky uses Supabase Auth (email + password). The mobile app uses supabase_flutter only to obtain / refresh the JWT; every BFF call then attaches that JWT as Authorization: Bearer.

① 起動時 — トークン復旧とセッション確認 1. On launch — restore session and verify

sequenceDiagram
  participant App as Flutter App
  participant Keystore as Secure Storage
(Keychain / Keystore) participant SbAuth as Supabase Auth participant BFF as Parky BFF (/v1/*) App->>Keystore: read refresh_token alt no token App->>App: show Sign in screen else has token App->>SbAuth: POST /token?grant_type=refresh_token SbAuth-->>App: { access_token, refresh_token, expires_in } App->>Keystore: save tokens App->>BFF: GET /v1/me
Authorization: Bearer BFF-->>App: 200 OK { user } App->>App: navigate to Home end

② 401 受信時 — refresh → 自動再試行 2. On 401 — refresh, then retry once

sequenceDiagram
  participant App as Flutter App
  participant SbAuth as Supabase Auth
  participant BFF as Parky BFF

  App->>BFF: GET /v1/parking-lots?near=...
Authorization: Bearer BFF-->>App: 401 { error.code: "unauthorized" } App->>SbAuth: POST /token?grant_type=refresh_token alt refresh OK SbAuth-->>App: { access_token } App->>BFF: retry GET /v1/parking-lots
Authorization: Bearer BFF-->>App: 200 OK { items } else refresh failed SbAuth-->>App: 400 invalid_grant App->>App: clear session, navigate to Sign in end
原則:401 の自動再試行は1 リクエストあたり最大 1 回。 refresh 自体が 400/401 を返したらログアウトして Sign in 画面へ誘導します。 refresh_token は端末の Secure Storage(Keychain / Android Keystore)に保存し、 アプリ削除時に失効する運用にしてください。 Rule: auto-retry at most once per request on 401. If the refresh itself fails (400/401), log out and go back to Sign in. Store the refresh token in platform Secure Storage (Keychain / Android Keystore) so it's invalidated when the app is uninstalled.

③ ログアウト/退会 3. Logout / account deletion

強制アップデート契約 Forced-update contract

サーバ側の仕様変更に追従できないクライアントを安全に締め出すため、全 API コールに バージョンヘッダを付けて BFF が強制アップデートを返せるようにします。

To keep obsolete clients from breaking, every BFF call carries a version header, and the server can force an upgrade when the client is too old.

項目Item 仕様Specification
クライアント送信ヘッダClient-side headers X-App-Version: 1.2.3X-App-Platform: ios|androidX-App-Build: 42
サーバ側判定Server-side check BFF が config.minimum_supported_version と比較し、不足なら 426 Upgrade Required を返却 BFF compares against config.minimum_supported_version; returns 426 Upgrade Required if too old
レスポンス形式Response shape
{
  "error": {
    "code": "upgrade_required",
    "message": "このバージョンはサポート対象外です",
    "request_id": "uuid"
  },
  "required_version": "1.3.0",
  "store_url": {
    "ios":     "https://apps.apple.com/app/idXXXXXXXX",
    "android": "https://play.google.com/store/apps/details?id=jp.co.parky.app"
  }
}
クライアント挙動Client behavior 426 を受けたら、すべての操作をブロックする全画面モーダルを表示。store_url への遷移ボタンのみ活性化 On 426, show a blocking full-screen modal; only the "Go to store" button is active
メンテナンスモードMaintenance mode 503 Service Unavailable + error.code: "maintenance" + Retry-After ヘッダ。ユーザーにはメンテナンス画面を表示 503 Service Unavailable with error.code: "maintenance" and a Retry-After header. Show a maintenance screen

横断規約 — 日時・ページネーション・エラー Cross-cutting conventions

日時フォーマット Date/time format

ページネーション Pagination

現状の OpenAPI は page + limit + total 方式(offset pagination)です。 モバイル側で無限スクロールを実装する場合は、下記のクライアント規約に従ってください。

The current OpenAPI uses offset pagination (page + limit + total). For infinite scroll on mobile, follow the client-side convention below.

エラー形式(統一) Error shape (unified)

BFF の全エンドポイントは下記形式でエラーを返します。詳細カタログは bff/errors.html

Every BFF endpoint returns errors in this shape. The full catalog lives at bff/errors.html.

{
  "error": {
    "code": "snake_case_code",
    "message": "human readable",
    "request_id": "uuid",
    "details": { ... }
  }
}
HTTPHTTP error.code 意味Meaning クライアント処理Client behavior
401unauthorizedJWT 不正 / 期限切れInvalid / expired JWTrefresh → 1 回だけ再試行Refresh → retry once
403forbiddenRLS で拒否Denied by RLS画面内エラー表示Show inline error
404not_found対象リソースなしResource not found空状態画面へShow empty state
409conflict状態遷移違反・冪等違反Invalid transition / idempotency violation最新状態を再取得し再試行判断Refetch and decide
422validation_error入力不正Invalid inputフィールドエラーとして表示Show as field-level error
426upgrade_required強制アップデートForced upgrade上記モーダルを出すShow the forced-upgrade modal
429rate_limitedレート超過Rate limitedRetry-After に従いバックオフBack off by Retry-After
503maintenanceメンテナンス中Maintenanceメンテナンス画面を出すShow maintenance screen

レート制限 Rate limits

ヘッダ規約(全リクエスト共通) Header conventions (on every request)

ヘッダHeader Value 必須Required
AuthorizationBearer <JWT>
X-App-Versionsemver 形式
X-App-Platformiosandroid
X-App-Buildビルド番号(整数)Build number (integer)
Accept-Languagejaen
User-AgentParky/<version> (<platform>)

OpenAPI への追補要望(既知の欠落) Known gaps in the OpenAPI

以下は本パック作成時点で OpenAPI 側に情報が欠けている項目です。 上記規約に従ってクライアント実装し、次版の OpenAPI で examples / operationId / 4xx schema 等を追加する運用とします。 The items below are known OpenAPI gaps at the time of this pack. Implement against the conventions on this page; a future OpenAPI revision will fill in examples, operationIds, and 4xx schemas.
次のステップNext: API 契約を理解したら、04. モバイルが触るデータモデル でデータ構造を確認してください。 Once the API contract is clear, head to 04. Mobile-facing data model.