こんにちは、WebエンジニアのYUUKIです。
今回は前回に引き続き、Webを支える技術の後編の要約まとめになります。
前回の1部から3部では、ハイパーメディアのHTTPとURIについてまとめました。
今回の4部と5部では、ハイパーメディアフォーマットのHTMLと、Webサービスの設計方法についてまとめます。
実際にWebサービスを作っている方には参考になる部分が多いと思いますので、自身の経験と照らし合わせて読んでみてください。
4部〜5部までの目次
- 4部 ハイパーメディアフォーマット
- 10章 HTML
- 11章 microformats
- 12章 Atom
- 13章 Atom Publishing Protocol
- 14章 JSON
- 5部 Webサービスの設計
- 15章 読み取り専用のWebサービスの設計
- 16章 書き込み専用のWebサービスの設計
- 17章 リソースの設計
4部 ハイパーメディアフォーマット
HTMLの概要から、XML文書に意味を持たせる技術のmicroformats、RSSで使用されるフォーマットのAtom、AtomベースでCRUDを実現するAtom Pub、データフォーマットのJSONについて、その仕様と使用例を解説している。
HTML
HTMLとは、タグ構造で書かれた構造化文書で扱われるマークアップ言語である。
メディアタイプには、以下の2つがある。
- text/html
- SGMLベース
- application/xhtml+xml
- XMLベース
HTMLを学ぶには、メタ言語である「XML」の基礎知識が必要。
XMLには要素と呼ばれるタグの纏まりがあり、要素名を開始タグ、終了タグで表し、その中で属性名、属性値、要素内容、といった形で表す。
<!-- 要素 -->
<開始タグ 属性名="属性値">
要素内容
</終了タグ>
<!-- 要素(ここまで) -->
構造化文書の中で要素は木構造になっており、大きな枠の要素を親要素、親要素の中にある要素を子要素、と呼ぶ
<親要素>
<子要素>
<子要素>
<子要素>
<親要素>
有名な要素として、親要素の「html」、その中の子要素としてヘッダ情報を示す「head」と「body」がある。
bodyには、大きな塊として「ブロックレベル要素」と、その中に入る「インライン要素」の2つがある。
ブロックレベル要素はh1やpなど、ある程度大きな塊の要素で、インライン要素はb要素やimg要素など、強調や改行、画像埋め込みなどを表現する小さな要素である。
他、リンクを示すものに、ブロック要素の中で使われるa要素、ヘッダの中でWebページ同士のリンクを表すlink要素がある。また、form要素を使えばGETでリソースを取得、POSTでリソースを作成することができる。
この章では、HTMLはハイパーメディアの一種なので、「URIとHTTPと組み合わせることで絶大な効果を与える」こと、HTMLでリンクを設計する際は、「リンクをたどることでアプリケーション状態が遷移すること」を意識する必要がある、と述べている。
microformats
microformatsとは、WebにおけるXML文書が意味を持つ「セマンティックWeb」を実現する為の技術のこと。
具体的には、XMLの中にclass属性などを用いて、XML文書に意味を持たせ、その意味をサーバが読み取れるようにする為の技術である。
microformatsを使った例に、クリエイティブコモンズがある。これは「著作物の配布が可能である」という意味を、XMLにmicroformatsを使って持たせることが出来るメタデータである。
他にも、SEO対策で使われる rel-nofollowがある。これは、link要素やa要素にrel-nofollow属性を持たせることで、「Googleのクローラーがリンクが貼られていることによるページランクを評価しない」ようにする為のメタデータである。
microformats以外にも、RDFというWeb上のリソースにメタデータを与えることで、それが意味を持つリソースとなる技術もある。しかし、これはmicroformatsに比べて冗長な表現になりがちで、かつ本データとは別のフォーマットで記述する必要がある理由から、現在ではあまり使われていない。
Atom
Atomとは、タイトル/著者/更新日時といったメタデータを、拡張可能なフォーマットとして表現できるメディアタイプのこと。XMLフォーマットの一つでもある。
主にブログのRSS技術で使われる。
Atomが開発されたのは、乱立したRSSの仕様を、拡張性をもたせたAtomフォーマットで統一しようとした経緯がある。
AtomはブログのRSS以外にも、検索エンジンや写真管理など様々なWebサービスのWebAPIとして使われている。それだけ汎用性の高いフォーマットである。
Atomは主に以下の2つで構成される。
- コレクションリソース
- feed要素で表現
- 表現できる内容
- faviconのアイコンロゴ
- logo要素
- メンバリソース
- entry要素で表現
- エントリリソース
- XMLで表現出来る
- メディアリソース
- 画像や動画など、XML以外で表現できるリソース
Atomは拡張性が高い。その例として、「OpenSearch」がある。OpenSearchはブログサービスに検索サービスを埋め込むことが出来るAPIを、プログラムとして付け加えることが出来るAtomの拡張技術である。
OpenSearchを利用することで、検索結果をresponse elementで表現することが出来る。(もし、OpenSearchを知らない普通のフィードリーダーであれば、OpenSearchで書かれた記述は無視され、通常のAtomフィードとして扱う)
その際には、一つのfeedに全てのentryを含めるのは現実的でない理由から、フィードを分割して表現する。
なお、フィードの種類には以下3つがある。
- 完全フィード
- 全てのエントリを一つの文書に含んでいる
- 一件のレスポンスを返す
- ページ化フィード
- エントリを複数の一時的な文書に分割している
- 1ページにつき10件で返すページネーション
- アーカイブ済みフィード
- エントリを複数の恒久的な文書に分割している
- 月別で記事を表示するアーカイブ
Atom Publishing Protocol
略してAtom Pub。Atom PubとはAtomをベースとしてリソースにCRUDする為のプロトコルである。
Atomがただのデータ・フォーマットに対して、AtomPubは実際にリソースが規定したフィードやエントリで表現するリソースのCRUDが出来る。
Atom Pubに対応したフレームワークやライブラリは数多く存在する。それらを使うことで、最初から新しいAPIを作る必要なく、既存のAtom PubというWebAPIを利用してブログサービスなどの様々なWebサービスを構築する事ができる。
Atom PubはRESTを元に設計されており、リソースモデルとリンク機構が適用されている。システム設計者はAtom Pubを利用することで、実装工数の大幅な削減や相互運用性を高めることが出来る。
Atom PubでCRUDを行うことの特徴として、以下がある。
- PUTでは、リクエスト時に仕様として知らない要素や属性も含めて、全ての情報を送る必要がある
- POSTでは、レスポンス情報にクライアントがPOSTしたエントリには入っていない要素(例えばlink要素)が追加されたりすることがある。
つまり、Atom Pubのサーバは、エントリのメタデータを自動的に追加/更新する可能性がある、ということである。
メディアリソースを操作する場合の特性として、以下がある。
- XML文書ではなく、メディアリソースの画像本体をPOSTする
- その際はSlugヘッダという、AtomにはないAtom Pubが新定義したヘッダを使って文字列を%エンコードする
他には、サービス文書と言って、コレクションリソースのメタデータを複数まとめて記述する方法などがある。
最後に、Atom Pubに向いているWebAPIをまとめる。
- 向いている
- ブログサービスのAPI
- 検索機能を持つデータベースAPI
- タグを使ったソーシャルサービスのAPI
- 向いていない
- AtomPubの特性を活かさないようなAPI
- タイトルや作者/更新日時などAtomフォーマットに必須なメタデータが不要なAPI
- データの階層構造が重要なAPI
- AtomPubの特性を活かさないようなAPI
WebAPIを開発する際は、Webサービスの特性に合わせて、ベースとなるプロトコルやデータフォーマットを選定する必要がある。
※文章だとわかりにくいので、詳しく知りたい方は以下のGoogleエンジニアが公開しているAtom Pubの紹介動画をご覧になるのをお勧めします。
JSON
JSONとはJavaScript Object Notationの略で、JavaScriptの記法でデータを記述出来るのが特徴のフォーマットである。
JSONはXMLと比べると、冗長性が低く、かつブラウザで実行できるため、Ajax通信(非同期通信)におけるデータフォーマットとしてよく使われている。
JSONはjson拡張子で扱われることが多い。よって、明示的にjson表現を記したい場合は、.jsonという拡張子をURIに含めるようリソースを設計すると良い。
JSONには、以下6つの組み込みのデータ型がある。ここでは、それぞれの仕様を解説する。
- オブジェクト
- 記法 {}
- 「”名前”:”値”」の組を、オブジェクトの「メンバ」と言う
- 配列
- 記法 []
- 文字列
- 記法 “”
- エスケープ処理が可能
- 数値
- 整数と浮動小数点数の両方を含める
- null
- 明示的に”null”とリテラルで表記する必要がある
- boolean
- 明示的に”true”と”false”をリテラルで表記する必要がある
なお、各メンバの名前は全て””で囲まれる。
下記がJSON記法の例である。
#"名前":"値"の組をオブジェクトの「メンバ」と言う
{
"name": {
"first": "Yuuki",
"last": "Tetsuya"
},
"blog": "https://tech.cloud-blazer.com",
"age": "26", #数値
"interests": ["Web", "XML", "REST"] #配列
}
他に、組み込みにはないが「日時」はUNIX時間(1970年1月1日)からの差分時間のGMT表記で書く必要がある。その際には、JSのDateクラスのToStringメソッドを使って時間を表すのが一般的。しかし、ブラウザによって表記が変わる為、より標準的な記法であるISO8601フォーマットで記す方が良い。
リンクは、絶対URIで示す。メンバは、hrefやlinkなどHTMLやAtomでもわかるような名前にしたほうが良い。
JSONには、クロスドメイン通信を行えるJSONPというリソース表現がある。
クロスドメイン通信とは、複数のドメインに属しているサーバにアクセスすることを指す。JSONPでは、このクロスドメイン通信を使って別ドメインにあるJSONデータを、JSONPを使って呼び出すことが出来る。
最後に、JSONを扱う上で重要な考え方を一つ挙げる。JSONはハイパーメディアフォーマットの一つであり、URI、HTTP、HTMLの3つのハイパーメディアの中の物であることを正しく理解すること。それを理解した上で、リンクを表現するメンバを入れるなどして正しく設計することが重要である。
5部 Webサービスの設計
Webサービスを設計するにあたって、読み取り専用と書き込み専用の2つの設計方法と、リソースの設計方法をまとめている。
読み取り専用のWebサービス設計
ここで言うWebサービスとは、FacebookやTwitterのようなユーザに直接触れられるサービスのことではなく、WebAPIのような、「開発者がアプリケーションと連動させて使用するプログラム」を含めた上で使っている。
Webサービスの設計の工程は幾つかに分かれるが、今回は「リソースの設計」に焦点を当てて解説する。リソースの設計とは、クライアントとサーバ間のインターフェイスの設計、つまりWebサービスやWebAPIの外部設計のことである。
Webサービスの設計では、どのようにリソースを分割し、URIで名前を付け、相互にリンクをもたせるかが設計の勘所となる。
具体的には、以下のステップでWebサービス設計を行う。
- Webサービスで提供するデータを特定する
- データをリソースに分ける
次に、各リソースに対して次の作業を行う。
- リソースにURIで名前を付ける
- クライアントに提供するリソースの表現を設計する
- リンクとフォームを利用してリソース同士を結びつける
- イベントの標準的なコースを検討する
- エラーについて検討する
この章では、Webサービス設計を「郵便番号検索サービス」を例に行っている。
なお、RESTful(アドレス可能性、持続性、統一インターフェイス、ステートレス性)の性質の考え方を元に設計する。
読み取り専用のWebサービス設計の各工程
- サービス要件を決め、Webサービスで提供するデータを特定する。
- データをリソースに分割する。リソース分割が最も難しい工程で、ここをしっかりとできればあとは成功したも同然である。
- 各リソースにURIで名前を付け、実際にクライアントに提供するリソースの表現を設計する。ここでは、データフォーマットにJSON、XML表現にXHTMLを使用する。XMLを選んだ理由としては、郵便番号データには著者情報や更新日時などのメタデータが必要ないからなのと、ブラウザで最低限表示出来ると便利だからである。JSONを選んだ理由としては、JSがメインのクライアントになる可能性が高いのと、クロスドメイン通信が行えるからである。
本章の最後には、リソースの設計はスキルであり、URIの設計方法、表現選択の指針、リンクの設計は身につける事ができるものだと述べている。
書き込み専用のWebサービス設計
書き込み専用のWebサービスは以下の手順で設計する。
- サービスのリソースの作成
- サービスのリソースの更新
- サービスのリソースの削除
- バッチ処理
- トランザクション
- 排他制御
サービスの作成/更新/削除
サービスの作成/更新/削除専用のリソース「ファクトリリソース」を作り、そのリソースに対して作成/更新/削除するデータをJSON形式でリクエストする。
基本的には、POSTで作成し、PUTで更新し、DELETEで削除する。
更新手法として、バルクアップデートとパーシャルアップデートというものがある。前者は更新する全体をPUTするもので、後者は一部分のみPUTする方法。
バッチ処理/トランザクション処理
バッチ処理とは、大量のデータを一度にまとめてリクエストすることである。
バッチ処理が出来るように、Webサービスを実装するのが望ましい。
バッチ処理では、エラーが起きた時の対処法に気をつける必要があるが、それはトランザクション処理によって補完出来る。その際は、トランザクション専用のリソース「トランザクションリソース」というファクトリリソースを作成して、その中でトランクザクション処理を行う。
排他制御
最後に排他制御で、これは複数のクライアントを相手にするWebサービスを作る場合に実装する。排他制御には悲観的ロックと楽観的ロックの2つがある。
・悲観的ロック
悲観的ロックはユーザをあまり信用しないで排他制御を行う方法で、WebDAVのLOCK/UNLOCKメソッドを使う方法と、独自のロックリソースを使う方法の2つがある。
・楽観的ロック
楽観的ロックはリソースの競合が起きた場合にのみ対処するロック方法で、そう頻繁に更新や削除が起きない場合に採用する。
実装には、条件付きPUT、採用付きDELETEを利用する。
この章のまとめとして、リソースの更新処理の設計について、「設計はバランスである」と述べている。その理由として、あちらを立てればこちらを立てず、過剰に品質を求めて納期が遅れてしまうことは元も子もない、かといって必要最低限の品質は満たす「バランス」が重要であるということである。
バランスの指針として、以下が重要だと筆者は述べている。
- なるべくシンプルに保つ
- 困ったらリソースに戻って考える
- 本当に必要ならPOSTで何でもできる
Webサービスの設計手法
Webサービスを設計するにあたって、一番気をつけなければならない点はWebサービスとWebAPIを分けて考えないことである。なぜなら、双方とも同じアーキテクチャスタイルの元で作られるものだから。
さらに、設計にあたってはWebAPIのリソース関係をそのままWebAPIに流用出来るように設計することも重要である。
Webサービスの設計は、オブジェクト指向の設計のようにベストプラクティスがあるわけではないが、幾つかの指向がある中で、今回はリソース指向アーキテクチャを使ったリソースの導出方法を紹介している。とともに、それ以外のアーキテクチャの種類、メリット・デメリットを紹介している。
リソース指向アーキテクチャとは
リソースを中心とする設計手法のこと。
リソース指向アーキテクチャ設計の注意点としては、Webサービスのデータを特定する方法と、データをリソースに振り分ける方法がわからないこと。これらを払拭する為に、情報アーキテクチャという、図書館情報学を元にした、受け手側が、書き手側が残した情報を手に取りやすくするよう考案された設計手法を利用することで、この情報アーキテクチャが、先程説明したリソース指向アーキテクチャの欠点を補完してくれる。
以上の理由から、リソース指向アーキテクチャと情報アーキテクチャの組み合わせが勧められている。
リソース指向アーキテクチャでは次のようにリソースを導出する。ここでは、リソース指向アーキテクチャの概念を使って、既存の関係モデルからリソースを導出する。
リソースの導出
まずは、中心となるテーブルからリソースを導出する。その際、URIに一意のIDを含める方法として、データの主キーを含めるケースと、主キー以外の一意のキーを含めるケースの2つがある。
本章では、後者を利用する。理由として、前者の方がリソースの導出方法として簡単ではあるが、今回の「郵便番号検索サービス」のような、郵便番号の値自体を一意のURIとして表した方が、クライアントから見たときのURIの可読性が向上するし、URIが変わりにくくなることが挙げられる。
リソースが持つデータの検討
次に、そのリソースが持つデータを検討する。
このステップで重要なのは、メインテーブルに全てのリソースを含めることである。その理由として、通常関係モデルでは正規化と言って、データの重複を防ぐ為に一つのテーブルに一つの情報のみ含めるが、リソースの設計では、あえて正規化を崩し、リソースが自己記述的に表現出来るようにする。
検索結果リソースの導出/階層の検討/トップレベルリソース/リンクによる結合
次に、検索結果リソースの導出と、階層/トップレベルリソースの検討と、
最後にリンクによる結合を行って関係モデルからのリソースの導出を完了させる。
関係モデルからのリソース導出の注意点として、トップレベルリソースの存在を忘れないことと、データの持つ階層構造を考えることが挙げられる。階層構造を持つのが大事な理由は、関係モデルは階層構造を持つのが苦手だからである。
他のアーキテクチャの種類とメリット・デメリット
他のアーキテクチャには、オブジェクト指向アーキテクチャがある。この指向からリソースを導出する注意点として、クラスの中にあるメソッドの処理内容をリソースとして表さないことが挙げられる。なぜなら、表してしまうと「Webサービス内部の情報が外部に表れてしまう」から。
最後に、WebAPIの設計では、「WebAPIとWebサービスを分けて考えないことが重要である」と本章でまとめられている。
Webを支える技術の4部と5部を読んでみて
AtomとAtom Pubについては実際に手で触れたことがない為、イメージがしにくかったのですが、Webサービスの設計ではベストプラクティスに近い設計手法を知ることが出来てとても参考になりました。
特に、リソース設計のリソース指向アーキテクチャでは、関係モデルからリソースを導出する手順と注意点を知ることが出来るので、実際のWebサービス開発に活かせる部分は多いと思います。
本書の内容の理解を深めるには、やはり自分でWebAPIをスクラッチ開発するのが一番良いと思いました。読んだだけでは、中々知識として定着しにくいですからね。
ただ、「WebAPIの設計にはこういうケースがある」というのを知っておくのと知らないとでは、Webエンジニアとしての実力に雲泥の差があると思うので、Webに関わる仕事をしている方は是非一度目を通しておくことをおすすめします。
コメント
[…] も兼ねて内容をわかりやすく要約していきます。※後半部分はこちら […]
[…] こちらの記事で書評しています。 […]