ファイル転送API設計:RESTfulベストプラクティス
RESTfulベストプラクティスに基づく堅牢なファイル転送APIを設計。認証、レート制限、マルチパートアップロード、エラー処理を解説。
適切に設計されたファイル転送REST APIは5〜6のリソース(セッション、パーツ、共有、ダウンロード、取消)を公開し、HTTPセマンティクスを正直に使用し(作成にPOST、べき等なチャンクにPUT、取消にDELETE)、実際のバイト移動を署名付きストレージURLにプッシュしてサーバーが帯域幅のボトルネックにならないようにする。認証はTLS 1.3上の短命ベアラートークンを使用し、レート制限は作成とメタデータ読み取りを区別し、チャンク分割アップロードはtus再開可能パターンまたはS3マルチパートセマンティクスに従い、エラーはRFC 7807 Problem Detailsに従いクライアントがプログラム的に処理できるようにする。経済産業省(METI)のセキュアプログラミングガイドラインも、APIレイヤーでの適切なエラー処理と認証実装を求めている。
ファイルでなくアクションを中心にリソースモデルを形成する
よくある間違いはAPIをファイルツリーとしてモデル化することだ。ファイル転送サービスは3つのリソースとしてよりよくモデル化される:
/sessions— 進行中のアップロード。POSTで作成され、チャンクのPUTで充填される/shares— 有効期限とダウンロード予算を持つ完了した、アドレス可能な転送/downloads— バイトをフェッチするための短命の署名付きアクセスハンドル
セッションはcompleteアクションで共有になり、共有は時間またはダウンロード予算で期限切れになる。取消は共有へのPATCHまたは取消トークン付きのDELETEだ。「ファイル」や「フォルダー」の名詞はない—それらはストレージの実装詳細であり、公開契約ではない。
認証と認可パターン
ユーザー向けAPIでは、EdDSAで署名された短命JWT(15分TTL)を発行し、セキュアなHttpOnlyクッキーでリフレッシュする。トークンはAuthorization: Bearerに入れ、ログに記録されるクエリ文字列には絶対に入れない。
マシン間では、HMAC-SHA256リクエスト署名がベアラートークンを上回る。鍵を送信せずに鍵の所有を証明するからだ。AWS SigV4が参照設計だ。
署名付きダウンロードURLのTTLは時間でなく分にする。15分のウィンドウは使いやすさと漏洩URLが転送されるリスクのバランスをとる。
チャンク分割アップロードとマルチパートセマンティクス
再開可能なチャンク分割アップロードには2つの信頼できるプロトコルがある:tus(IETF草案、Upload-OffsetとUpload-Lengthヘッダー)とS3マルチパート(PartNumber、UploadId、ETag)。1つを選んで継続すること。独自プロトコルの発明は魅力的に見えて、部分書き込み、順序外チャンク、放棄されたセッションを処理する必要が出たときに悪くなる。
tus.ioのパターンをREST形式で:
POST /sessions -> 201, Location: /sessions/abc
HEAD /sessions/abc -> 200, Upload-Offset: 104857600
PATCH /sessions/abc -> 204, body = 次のチャンク
POST /sessions/abc/complete -> 201, Location: /shares/xyz
DELETE /sessions/abc -> 204
チャンクサイズの境界:S3マルチパートと一致する5MB最小、リトライコストを制限する100MB最大、デフォルト8MB。アドバタイズされたオフセットと一致しないチャンクは、期待されるオフセットを説明するProblemドキュメントと共にHTTP 409 Conflictで拒否する。
現実の悪用を反映したレート制限
レート制限はエンドポイントのコストで変わる必要がある:
POST /sessions:IPあたり時間20件(高コスト—ストレージを割り当てる)PATCH /sessions/:id:セッションあたり時間10,000件(低コスト—バイトを書き込む)GET /shares/:id:IPあたり時間1,000件(メタデータルックアップ)GET /shares/:id/download:IPあたり時間100件(エグレスコスト)
エッジ(Cloudflare、Fastly)でフロア保護のためにレート制限を適用し、バースト制御のためにアプリケーション(express-rate-limit、Fastifyの@fastify/rate-limit)で2番目の層を適用する。秒単位でRetry-After付きの429を返す。成功レスポンスにもレート制限ヘッダーを含める:
RateLimit-Limit: 20
RateLimit-Remaining: 17
RateLimit-Reset: 2843
クライアントが処理できるエラーレスポンス
RFC 7807 Problem Detailsが標準だ。すべてのエラーはContent-Type: application/problem+jsonを返す:
{
"type": "https://api.example.com/errors/chunk-offset-mismatch",
"title": "Chunk offset mismatch",
"status": 409,
"detail": "Server expected offset 5242880, received 4194304.",
"expected_offset": 5242880,
"session_id": "abc123"
}
type URIはクライアントがパターンマッチングに使うため、文書化され安定している必要がある。カスタムフィールドがマシン処理可能なコンテキストを追加する。エラーにスタックトレース、ファイルパス、または内部IDを決してリークしないこと。
バージョニングと負債の蓄積防止
ヘッダーでなくURLパス(/v1/sessions)でバージョニングする。パスバージョニングはログで可視で、キャッシュ可能で、Accept: application/vnd.example.v1+jsonよりデバッグが容易だ。v2がリリースされてから少なくとも24ヶ月間はv1をサポートする。フィールドを自由に追加する(クライアントは不明なフィールドを無視する必要がある)が、安定バージョンではフィールドを削除したりリネームしたりしない。
HexaTransferのAPIはこれらのパターンに従っている—短いリソース、tus.ioスタイルのチャンクアップロード、Problem Detailsエラー、15分の署名付きダウンロード、RateLimitヘッダー。詳細は https://hexatransfer.com で。無料、アカウント不要、最大10GB。
エンドツーエンド暗号化で大容量ファイルを安全に送信
エンドツーエンド暗号化で最大10GBのファイルを無料で転送。アカウント不要。ファイルはアップロード前にブラウザで暗号化されるため、他の誰にも読まれません。
ファイルを送信