[読書] Webを支える技術
RESTful
設計
読んだ本
Webを支える技術―― HTTP、URI、HTML、そしてREST |
モチベーション
- mozaic.fm ep7 REST の回をきいて、RESTをきちんと理解するための本としての良書として読むことにしました。
- そろそろクラウドまわりのスキルをきちんと強化したくなったので、そのうえでRESTはきちんと基礎から頭に入れておくべきところかなと。
かかった時間など
- 2023/2/27 〜 2023/4/28
- 6時間くらい
- 途中microformatsやAtomの部分は読み飛ばしてこのくらいでした。
理解メモ(復習)
第1部. Web概論
- Webとはなにか
- Webの歴史
- 最初インターネット標準はIETFのRFCで定められていたが、急速な進歩でおいつかずW3Cが発足
- SOAP → REST(Google,amazon)へ
- REST ー Webのアーキテクチャスタイル
- RESTはアーキテクチャスタイル。リソース指向アーキテクチャ
- ULCODC$SS=REST。以下の6つの要素をもつ
- クライアント/サーバ
- ステートレスサーバ
- キャッシュ
- 統一インターフェース
- 階層化システム
- コードオンデマンド
第2部. URI
- URIの仕様
- RFC3986
- 使用可能な文字
- 英字
- 数字
- 記号:-.~:!$&'()
- ASCII文字以外を使う場合は
%-Encoding
というのを使う
- URIの長さ
- 仕様上の制限はない
- IEの実装上の制限2,038バイトが実質的な最大長
- スキーム
http
/https
など- IANAのページ に公式の定義の一覧がある
- ベースURI
- HTMLの
<base>
タグでベースURIを定義が可能。これをやっておけばCSSやJSへのパスを相対パスで書ける 対パスで書ける
- HTMLの
- %-Encoding (%エンコーディング)
- ASCII文字以外をURIに使うときにつかう
- UTF-8以外も可能で、元のページのエンコーディングをつかう
- URIの設計
- URIは、コロコロ変えることができないのが前提。1年以上経つと見れなくなっているなどは良くない
- 変わりにくいURIを設計するための原則:
- プログラミング言語に依存した拡張子やパスを含めない
- メソッドやセッションIDを含めない
- URIはリソースを表現する名詞にする
- URI設計のテクニック
- 拡張子で表現を指定する
- 特定の技術に依存する拡張子は悪だが、日本語と英語の切り替えなど、技術に依存しない場合は拡張子が有効
- コンテントネゴシエーションでやる方法もある。HTTPヘッダの
Accept-Language
で言語の優先度のリクエストが飛んでくるのでそれに合わせて返す
- マトリクスURI
- 緯度と経度のように階層構造にできないパラメータをURIに含めるときに有効
- セミコロンかカンマで区切るのが現在では一般的
- 拡張子で表現を指定する
- URIの不透明性について
- クライアントからは内部構造を意識した呼び出しをしないようにしたい。
- W3Cが発行している Architecture of the World Wide Web, Volume One の2.5節を参照
第3部. HTTP
- HTTPの基本
- HTTP/1.0:リクエストとレスポンスの1回の通信ごとにTCPコネクションを張っていた。
- HTTP/1.1:RFC2616。 1つのTCPコネクションで複数のコマンド・応答ができるようになった。
- (HTTP/2) → 本書には記載がないが、把握しておく。RFC7540で規定。1つの接続での並列処理、バイナリデータの使用による送受信のデータ量の削減、ヘッダ圧縮、サーバープッシュによりネットワークリソースの効率化ができる
- (HTTP/3) → QUICをつかった通信
- HTTPメソッド
- 8種類のみ
- GET:リソースの取得
- HEAD:メッセージヘッダだけを取得
- POST:データの登録
- PUT:データの保存
- DELETE:データの削除
- OPTIONS:リソースがサポートしているメソッドの取得
- TRACE:リクエストメッセージをクライアントに戻す
- CONNECT:プロキシ動作のトンネル接続への変更
- べき等性:ある操作を何回おこなっても結果が同じ
- 安全性:操作対象のリソースに副作用がないこと
- 8種類のみ
- ステータスコード
- 分類
- 1xx:処理中
- 2xx:成功
- 3xx:リダイレクト
- 4xx:クライアントエラー
- 5xx:サーバエラー
- (各コードはObsidianに直接まとめたので、割愛)
- 分類
- HTTPヘッダ
- (各種類はObsidianに直接まとめたので、割愛)
第4部. ハイパーメディアフォーマット
HTML
- (とくに目新しい発見はなかったので、割愛)
JSON
- RFC4627
- データ型:以下の6つが使える
- Object
- 配列
- 文字列
- 数値
- boolean
- null
- オブジェクト型
- 名前と値の集合
- 名前の型は常に文字列
- 中括弧
{
でくくる - メンバーは
,
で区切る - 名前と値は
:
で区切る
- 配列型
- 角括弧
[
で括る - 中の値は、すべてが同じ型でなくてもよい
- 角括弧
- 文字列
- ダブルクォートで括る
\uXXX
の形式でエスケープできる- バックスラッシュは
\\
- 改行は
\n
- 数値
- 整数、小数表現OK
- 指数表記もOK
- boolean
- 全部小文字の
true
またはfalse
のみ
- 全部小文字の
- null
- 小文字の
null
がリテラルになっている
- 小文字の
- 日時
- 日時のデータ型はないので、以下の2つの方法で実現
- エポック/UNIX時間を数値型にする(タイムゾーン情報が扱えない)
- ISO8601 形式の文字列にする
- 日時のデータ型はないので、以下の2つの方法で実現
- JSONP:クロスドメイン通信を実現する手法
第5部. Webサービスの設計
読み取り専用のWebサービスの設計
- リソース設計
- WebサービスやWeb APIの外部仕様を設計すること
- リソース設計のポイント
- どのようにリソースを分割するか
- どのような名前=URIをつけるか
- どのように相互にリンクもたせるか
- デザインドキュメントとして以下を記載すべき
- リソースの種類
- リソースの表現
- リソースとリソースのリンク関係
- リソース指向アーキテクチャの設計手順
- webサービスで提供するデータを特定する
- データをリソースに分ける
- リソースにURIで名前をつける
- クライアントに提供するリソースの表現を設計する
- リンクとフォームを利用してリソース同士を結びつける
- イベントの標準的なコースを検討する
- エラーについて検討する
- RESTfulなWebサービスの性質
- アドレス可能性:URIさえあれば、リソースを一意に指し示すことができる
- 接続性:リソースをリンクで接続し、1つのアプリケーションをなす
- 統一インタフェース:基本のメソッド(GET/POST/PUT/DELETE)だけ
- ステートレス性:実施はcookieをつかう。これにこだわりすぎて使いにくくならないようにすべし
書き込み可能なWebサービスの設計
- ファクトリリソースにPOSTする方法とリソースを直接PUTする方法がある
- 更新方法
- バルクアップデート:更新する項目以外の項目を含めたリソース全体を送信する方法
- パーシャルアップデート:差分だけを送信する方法
- どちらもサポートされているのがよい
- トランザクション制御
- RESTfulにするには、トランザクションリソース を活用する
- トランザクションの開始
- POST /transaction などとして作成したリソースID=トランザクションリソースをレスポンスで返す
- トランザクションリソースへの対象処理の追加
- PUT /transaction/308/1 、PUT /tranzaction/308/2、PUT /tranzaction/308/3などとして、1トランザクションでやりたい操作を追加していく
- トランザクションの実行
- PUT /tranzaction/308 などとして、ボディに
commit=true
をいれてリクエストしてもらう
- PUT /tranzaction/308 などとして、ボディに
- トランザクションリソースの削除
- DELETE /transaction/308 で削除
- 排他制御
- 悲観的ロック(Pessimistic Lock)
- 方法1:WebDAVのLOCK/UNLOCKメソッドをつかう
- まずはLOCKメソッドを呼び出す。ロックトークンを取得する。永久ロックされないようにタイムアウトを指定
- リソースの更新時にIfヘッダに取得したロックトークンを入れる
- UNLOCKメソッドを送ってロック解除。Lock-Tokenヘッダにロックトークンを指定
- 方法2:独自のロックリソースをつかう
- ロックリソース取得のためのPOSTリクエストを実行。ロックの種類(排他ロック/共有ロック)とタイムアウトだけを送るように単純化
- ロックをかけたユーザだけが編集できるようにサーバーの処理をつくる。タイムアウトもサーバー側で。
- 最後DELETEリクエストでロックリソースを削除する
- ロックされたときに返すHTTPレスポンスコードは、400でもよいが、WebDAV拡張の
423 Locked
が明示的でおすすめ。
- 楽観的ロック(Optimistic Lock)
- 条件つきPUTをつかう
- GETリクエストでまず更新対象のリソースのLast-ModifiedかETagの値から最終更新日時を調べる
- 更新時にIf-ヘッダに条件を指定する
- If-MatchやIf-Modified-Since、If-Unmodified-Sinceヘッダが使える
- DELETEでも同様にIf-ヘッダがつかえる
- 条件が合わないときに消すHTTPレスポンスコードは
412 Precondition Failed
- 排他エラー時におこなうべき動作
- 競合を起こしたユーザに通知して、確認してもらった上で更新、削除する
- 競合を起こしたデータを競合リソースとして別リソースに保存(PUTのみ)
- 競合を起こしたユーザに変更点を伝え、マージを促す(PUTのみ)
- 差分をとれる仕組みが必要
リソースの設計
- リソースの設計の方法は『RESTful Webサービス』でも言及されていない。本書では3つのパターンで方法を詳細
- 関係モデルからの導出
- 導出したER図の中心となるテーブルの1レコードを、1リソースにする
- これだとサーバ側のテーブル構造の都合にクライアントが引っ張られやすいデメリットがある
- 検索結果のリソースを導出=これはシナリオから導き、RDBMSのSQLに結びつけて考える
- 階層構造のリソースは導きにくいので、別途仕様書や設計書から導きだすしかない
- リンクによる結合は、ER図のリレーションシップを参考にできる
- オブジェクト指向モデルからの導出
- 主要なクラスの1つ1つのインスタンスが、1リソースに対応する
- 操作結果のリソース導出:クラスのメソッド操作自体をリソースにしないようにするべき
- 1対多の関係から、階層構造のリソースを導出
- リンクによる結合は、参照をもとに検討できる
- 情報アーキテクチャからの導出
- 情報アーキテクチャとは、「webページのように、リンク遷移する構造の中で情報を探しやすくするための設計」のこと
- 『Web情報アーキテクチャ第2版』に詳細が書かれている
- WebサービスとWeb APIを分けて考えない、というのがリソース設計で最も重要
感想
- Web開発必須前提知識がここに!
- REST APIを設計することにフォーカスして、それに必要な前提となる知識を得ることができる本でした。
- いつもなんとなくでWeb APIを追加してしまっていましたが、きちんとしたガイドラインをもって設計をするための知識をえることができました。
- ちょっと古い内容も、、
- HTTP/2以降の言及がなかったり、Atomに関する記載などが。他にも「今の時代ではもう古い」というのがないか不安になりますね。改訂を期待したいところです!w
今後の展望
- Web開発の現場ではあるべき姿を考えるうえで、この本は多用されると思われるので、何度も復習が必要そうです。現場での作業でちょくちょく見返したいです。
- こちらの本のベースになっている『RESTful Webサービス』も持っておくと良さそうです。読めるかはべつですが(^^;)
- 本書では詳しく書いていないのですが、『Web情報アーキテクチャ第2版』も第17章 リソース設計の考え方をスタディするうえで参考になりそうです。
最終更新日: May 4, 2024