
t0mmy
学習履歴詳細
APIデザインパターン 17章 コピーと移動 読了
やったこと
- APIデザインパターン 17章 コピーと移動 読了
学んだこと
ポイント
- コピー・移動処理が複雑になる要因
- コピー・移動処理実装時における、考えるべき点
学び
- コピー・移動処理は、動作要件や制限事項が多く、正しく実装することが困難
- 場合によっては、実装を避けることも選択肢に入る
- 独立したリソースのコピー・移動処理はそこまで難しくない
- 子リソースを持つ場合や、関連リソースをサポートしている場合、リソースのコピー・移動は、考えるべき問題が多くなる
- 特に移動(再配置)は、複雑な問題を抱えるため、可能な限りサポートするべきではない
- これといった、確実な解決策は存在しない
- 要件に応じて、コピーや移動ロジックは変化する可能性が高い
- 移動処理の実装は、慎重に検討すること
- 特に、親をまたいだリソースの移動は、リソースレイアウトに問題がある可能性が高い
- => リソースレイアウトから見直すこと
気づき
- 移動による参照更新について、リダイレクトテーブルを持つのはどうだろう?
- 「移動前のリソース => 移動後のリソース」 的なエンティティを持つイメージ
- どうしても参照を切りたくない場合は、有効かも
メモ
API 利用者が、リソースのコピーと移動を望む可能性は非常に高い。
APIにおける、リソースのコピーと移動を安全かつ確実に実行する方法を見ていく。
概要
リソースのコピーと移動は、カスタムメソッドで実装する。
コピーと移動の実装に際して、以下の点がポイントとなる。
- IDは利用者が指定する?サービス側で採番する?
- 古い識別子はどうする?
- 親をまたぐ場合とそうでない場合に違いはある?
- 親をまたぐ : 別の親に属しているだけで、以前と同じ識別子が必要な場合
- そうでない : 識別子を変更できれば良い
- 子リソースを持つ親リソースをコピーする場合、子リソースはどう扱う?
- コピー(または移動)中、該当リソースを、他のユーザが操作できないようにするには?
- アクセスポリシーを始めとしたメタデータをどう扱う?
実装
識別子
一般的には、サービス側で識別子を発行する方が良い。
- 識別子の生成をコントロールできるため
コピー処理の場合、create
メソッドと同じように動作させる。
- サービス側で識別子を発行している場合は、利用者側で識別子を指定できないようにする
- 利用者側で識別子を指定できる場合は、
copy
メソッドでも指定できるようにする- 指定した識別子が使用済みの場合は、
409 Conflict
エラーを発生させ、処理を中断する
- 指定した識別子が使用済みの場合は、
移動処理の場合は、目的は大きく「親リソースの変更」と「リネーム」に大別できる。
- 親子関係をもつリソースであれば、 「親リソースの変更」を目的とした移動処理は実装する価値あり
- 利用者指定識別子をサポートするのであれば、「リネーム」を目的とした移動処理は実装する価値あり
- 親子関係を持ち、利用者指定識別子をサポートするのであれば、両方を目的とした移動処理を実装できる
- 反対に、どちらも満たさないのであれば、そもそも移動処理を実装するべきではない
子リソースの扱い
コピー・移動処理のどちらでも、子リソースもまとめて扱う。
「コピーされたリソースは、コピー元と同じように振る舞うこと」という考え方が大事。
- 子リソースに手を加えない ... ということは基本ない
- 子リソースがあることを前提とした親リソースなどが機能しなくなるため
ただし、移動処理の場合、移動前のリソース識別子がリンク切れとなる。
関連リソース
◇ここでいう関連リソース
「コピー(または移動)したいリソース」を参照しているリソースのこと
リソースをコピー(または移動)する場合、関連リソースをどう扱うかが問題となる。
こうだ!という具体的な解決策はないため、問題点を明示する。
◇参照の整合性問題
リソースをコピー(または移動)する場合、コピー(または移動したい)リソースを参照するすべての関連リソースについて、関連リソースが持つ参照情報を更新するか決定する必要がある。
更新するためには、変更を追跡する必要があるが、これが非常に困難なのは想像に難くない。
◇関連リソースを複製するべきか問題
コピー(または移動)したいリソースに応じて、関連リソースの挙動も変化する。
- 関連リソースが持つ参照情報を更新する場合もあれば、関連リソースもコピーする必要がある状況も考えられる
つまり、リソースのコピー(または移動)に伴う関連リソースの更新処理は一定ではなく、アプリケーションの仕様によってほぼ確実に変化する。
Message リソースを含むChatRoomリソースをコピーする場合 ...
- Messageリソースの参照を持つ関連リソースは、コピー後のMessageリソースの参照を保持する
- ChatRoom リソースに所属するUser リソースは、複製してはならない
◇外部参照
具体的には、あるAPIのリソースを、インターネット越しの外部アプリケーションが参照している状況を考える。
以下の理由により、深く考えない。
- 外部アプリケーションの参照までサポートすることは不可能
- Webは基本的にベストエフォート
- 問題があれば何が起こるか想像がつく
- 問題があれば 404 が返ってくることを知っている
外部データ
◇ここで言う外部データ
DB管轄外かつアプリケーションが管轄するデータ(主にストレージ上のファイル)
リソースのコピー(移動)に合わせて、外部データもコピー(移動)するべきか。
アプリケーションの要件に従うことは大前提として、基本的にはプログラムでいう「参照コピーか値コピー」と同じ問題。
継承されるメタデータ
リソースのコピーによって、新たな(制約を含む)メタデータを作成することがある。
この時、コピー後のリソース次第では、コピーしたリソース(特に子リソース)が、新しい制約に違反する可能性がある。
例)
- コピー前 (Chatroom) のMessageリソースは text が140文字まで
- コピー後 (NewChatroom) のMessageリソースは text が 100文字まで
=> Chatroom の Messageのうち、100文字を超えるMessageが、NewChatroomでは制約違反に
この場合、制約に違反しているとして、コピー処理を拒否すると良い。
- 利用者側で、「新しい方の制約を見直す」や「データを修正する」などの対応を選択できるようにする
他にも、以下のような対応策が考えられるが、あまりよろしくない。
- Messageリソースが、制約を破れるようにする
- Messageリソースに対する update がうまく機能しなくなる可能性がある
- 制約に合うよう、Message リソースを修正する
- 利用者が不利益を被る可能性がある
アトミック性
コピー処理でアトミック性を担保する場合を考える。
システムが提供するスナップショット機能を使用する選択肢がある。
使用しているシステムデザインスナップショット機能が提供されていない場合、以下の選択肢がある。
- アトミック性を保証しない
- 書き込みロックを実施する
- copy 処理を対象としたDoS攻撃が成立する、というデメリットがあるため非推奨
移動処理でアトミック性を担保する場合を考える。
基本的には、コピー処理と同じ方法を採択する。
コピー処理と違い、 アトミック性を保証しない
という選択は、データの更新に失敗する危険性をはらむため、極力選択しないこと。
トレードオフ
「コピーを実装したい」という要件は十分考えられる。
リソースの移動は、慎重に検討する。
- 親をまたいだリソースの移動は、リソースレイアウトが問題の可能性有り
- まずはレイアウトの見直しから
- 不適切な識別子や、参照関係とすべきところを親子関係で表現している ... といったことが原因の可能性が高い
扱うこと
- API内のリソースの場所を変更する、「コピー」と「移動」カスタムメソッドの使用方法
- コピーと移動の操作について、適切な識別子(または識別子ポリシー)を決める
- 親リソースをコピー・移動する場合の、子リソースの扱い
- コピー・移動されたリソースに対する、外部からのデータ参照を処理する
- コピー・移動メソッドにはどのようなアトミック性が必要か
まとめ
- API 利用者が、リソースの複製・再配置を望む可能性は非常に高い
- リソースの複製・再配置は、標準メソッドではなく、カスタムメソッド(
move
やcopy
)を使用する - 親リソースに対する複製・再配置は、子リソースにも同じように適用されるべき
- ただし、これはケースバイケース
- どのようなケースでも、複製・再配置したリソースへの参照は、最新の状態に保つべき
- リソースが外部データを扱う場合、APIメソッドは、以下を明確化する必要がある
- 複製されたリソースが参照コピーか、値コピーか
- 複製・再配置カスタムメソッドは、(基礎となるストレージシステムの制約を考慮しつつ)できるだけアトミック性を保つこと
2023年07月30日(日)
2.0時間