SlideShare a Scribd company logo
1 of 65
Download to read offline
HYPERMEDIA: 
THE MISSING ELEMENT 
to Building Adaptable Web APIs in Rails 
ハイパーメディア: RailsでWeb APIをつくるには、これが足りない 
Toru Kawamura 
@tkawa 
! 
RubyKaigi 2014 
RESTful Web APIs 読書会 #19 2014.10.09
@tkawa 
Toru Kawamura 
• フリーランス Ruby/Rails プログラマ 
• Technology Assistance Partner at 
SonicGarden Inc. 
• REST厨 (RESTafarian) 
inspired by Yohei Yamamoto (@yohei) 
• Sendagaya.rb 共同主催 
• “RESTful Web APIs” 
読書会主催
Web API
“Web” 
http://www.opte.org/the-internet/
http://pixabay.com/en/spider-web-net-grid-silk-drops-13516/ 
「クモの巣」
https://www.flickr.com/photos/tamaki/260594564/ 
「クモの糸」
• プライベート 
• 内部から使われる 
• SPAや専用の 
クライアントが使う 
• だいたい予想できる 
コントロールできる 
• パブリック 
• 外部から使われる 
• 汎用的な目的の 
クライアントが使う 
• 予想しづらい 
コントロールしづらい
– 「WebAPIのこれまでとこれから」by @yohei 
http://www.slideshare.net/yohei/webapi-36871915
今回は「クモの巣」メインの 
話です 
http://pixabay.com/en/spider-web-net-grid-silk-drops-13516/
Change
変化は避けられない 
! 
Web APIは変化に適応しなければならない
2種類の Change 
バージョンが変わるバージョンが変わらない 
互換性がない互換性がある 
クライアントを壊すクライアントを壊さない
2種類の Change 
バージョンが変わるバージョンが変わらない 
互換性がない互換性がある 
クライアントを壊すクライアントを壊さない 
壊す Change 壊さない Change
壊すChangeはよくない 
• ひどいユーザ体験を生む 
• クライアント開発者にコードの書き直し・ 
再デプロイを強いる 
• もし     だったら…
なぜ起こる? 
バージョンが変わるバージョンが変わらない 
互換性がない互換性がある 
クライアントを壊すクライアントを壊さない 
壊す Change 壊さない Change
人間が読める説明書から作られる 
クライアントがたくさんある 
GET /v1/statuses?id=#{id} GET /v1/statuses?id=#{id}
GET /v2/statuses/#{id} GET /v1/statuses?id=#{id} ×コードの書き直しが必要
機械が読める説明書から作られる 
クライアントもある 
{ 
"apiVersion": "1.0.0", 
"basePath": "http:// 
petstore.swagger.wordnik.com/api", 
"resourcePath": "/store", 
"produces": [ 
"application/json" 
], 
"apis": [ 
{ 
"path": "/store/order/{orderId}", 
"operations": [ 
{ 
GET /v1/statuses?id=#{id} GET /v1/statuses?id=#{id} 
"method": "GET", 
"summary": "Find purchase order 
by ID", 
"notes": "For valid response 
try integer IDs with value <= 5. Anything 
above 5 or nonintegers will generate API 
errors", 
"type": "Order", 
"nickname": "getOrderById", 
"authorizations": {}, 
"parameters": [
GET /v2/statuses/#{id} GET /v1/statuses?id=#{id} ×コードの再生成が必要 
{ 
"apiVersion": "2.0.0", 
"basePath": "http:// 
petstore.swagger.wordnik.com/api", 
"resourcePath": "/store", 
"produces": [ 
"application/json" 
], 
"apis": [ 
{ 
"path": "/store/order/{orderId}", 
"operations": [ 
{ 
"method": "GET", 
"summary": "Find purchase order 
by ID", 
"notes": "For valid response 
try integer IDs with value <= 5. Anything 
above 5 or nonintegers will generate API 
errors", 
"type": "Order", 
"nickname": "getOrderById", 
"authorizations": {}, 
"parameters": [
{ 
uber: { 
version: "1.0", 
data: [{ 
url: "http://www.ishuran.dev/notes/1", 
name: "Article", 
data: [ 
{ 
name: "articleBody", 
value: "First note's text" 
}, 
{ 
name: "datePublished", 
value: null 
}, 
{ 
name: "dateCreated", 
value: "2014-09-11T12:00:31+09:00" 
}, 
{ 
name: "dateModified", 
value: "2014-09-11T12:00:31+09:00" 
}, 
{ 
name: "isPartOf", 
rel: "collection", 
url: "/notes"
{ 
uber: { 
「密結合」が原因 
version: "1.0", 
data: [{ 
url: "http://www.ishuran.dev/notes/1", 
name: "Article", 
data: [ 
• APIの変更がクライアントに反映されればよい 
{ 
name: "articleBody", 
value: "First note's text" 
}, 
{ 
name: "datePublished", 
value: null 
}, 
{ 
name: "dateCreated", 
value: "2014-09-11T12:00:31+09:00" 
}, 
{ 
name: "dateModified", 
value: "2014-09-11T12:00:31+09:00" 
}, 
{ 
name: "isPartOf", 
rel: "collection", 
url: "/notes" 
• APIの説明を分割して各レスポンスに埋め込む 
のが良い方法 
• APIについての多大な仮定は密結合を生む
バージョンが変わるバージョンが変わらない 
互換性がない互換性がある 
クライアントを壊すクライアントを壊さない 
壊す Change 壊さない Change 
密結合による疎結合による
例で見る疎結合: FizzBuzzaaS 
• by Stephen Mizell 
http://fizzbuzzaas.herokuapp.com/ 
http://smizell.com/weblog/2014/solving-fizzbuzz-with-hypermedia 
• サーバは与えられた100までの数の 
FizzBuzzを計算できる 
• サーバは次のFizzBuzzが何になるか知っ 
ている 
• クライアントは1から最後まで順番にす 
http://sef.kloninger.com/posts/ べてのFizzBuzzが欲しい 
201205fizzbuzz-for-managers. 
html
密結合なクライアント 
answer = HTTP.get("/v1/fizzbuzz?number=#{i}") 
puts answer 
end 
"/v2/fizzbuzz/#{i}" 
(1..1000) 
(1..100).each do |i| 
• すべてのURLとパラメータがハードコードされている 
• カウントアップのような、サーバロジックと同じこと 
をクライアントでも行っている
疎結合なクライアント 
root = HTTP.get_root 
answer = root.link('first').follow 
puts answer 
while answer.link('next').present? 
answer = answer.link('next').follow 
puts answer 
end next リンクが重要 
• ハードコードされたURLなし 
• URLや条件を変えてもクライアントは壊れ 
ない
• 実際にリンクをたど 
る代わりに、 
埋め込みリソースを 
使うことで 
リクエスト数を減ら 
すことが可能 
http://techlife.cookpad.com/entry/2014/09/08/093000
「APIコール」のメタファーは危険 
• クライアントがあらかじめURLとパラメータを用意 
してAPIを呼ぶ、というRPCのようなパラダイムから 
離れよう 
• クライアントが次にすることは、レスポンスの中の 
リンクから選ぶこと 
== ハイパーメディア
これは想像上のものではなく 
すでにHTMLにある
HTMLのWeb 
• WebアプリやWebサイ 
トはずっと変わり続け 
ているが、ブラウザは 
壊れていない 
• HTMLのWebでは、なぜ 
HTMLのリンクブラウザは壊れない? 
http://www.youtypeitwepostit.com/messages
HTMLの中のデータ 
• HTMLが表現する意味は 
「ヒューマンリーダブルなドキュメント」 
• 段落、リスト、表、セクション、… 
• これが人間にゆるく伝わればよい
HTMLの中のワークフロー 
• Webアプリはワークフ 
ロー(の提案)を含む 
• ワークフローは一連の 
画面遷移で表現される 
— リンク と フォーム 
”RESTful Web APIs” p.11 Figure 1-7
ハイパーメディアはワークフローを示す 
• 各画面は次に何ができる 
かの「メニュー」としてリ 
ンクやフォームを含む 
• ブラウザはその「メニュー」 
の中から選んで次へ進む 
• これがハイパーメディア 
で、FizzBuzzaaSもやってい 
たこと 
3 
4
もしHTMLにリンクがなかったら? 
代わりにワークフロー手順書がある? 
• 各WebアプリごとにURLやパラ 
メータをハードコードした専用 
クライアントを作りたくなる 
• クライアントとサーバのコード 
が密結合して、変更できない 
Webアプリになってしまう 
• これが今のWeb APIがやってい 
ること 
メッセージWebアプリ利用の手順書 
1. アドレスバーに /messages と入力し 
て GET 
2. アドレスは /messages のまま、 title 
と body のパラメータに文字列を 
セットして POST 
3. message-id を受け取って、アドレス 
バーに /messages/{message-id} と入 
力して GET
クローラにはもう1つヒントが 
• クローラはリンクをたどる(submitできるフォームもある) 
• クローラはHTMLドキュメントの中にあるデータと 
その「意味」を理解している 
• どうやって? 
https://support.google.com/webmasters/answer/99170
Microdata
Microdata 
<div itemscope itemtype="http://schema.org/Person"> 
My name is <span itemprop="name">Bob Smith</span> 
but people call me <span itemprop="nickname">Smithy</span>. 
Here is my home page: 
<a href="http://www.example.com" itemprop="url">www.example.com</a> 
I live in Albuquerque, NM and 
work as an <span itemprop="title">engineer</span> 
at <span itemprop="affiliation">ACME Corp</span>. 
</div> 
• 構造化データをHTMLドキュメントに埋め込むしくみ 
• データを変えることなくドキュメントの構造を変えられる 
• データをURLに結びつけることで、大まかな「データの意 
味」も表す(これもリンクの一種)
Microdata 
<div itemscope itemtype="http://schema.org/Person"> 
My name is <span itemprop="name">Bob Smith</span> 
but people call me <span schema.itemprop="org 
nickname">Smithy</span>. 
Here is my home page: 
<a href="http://www.example.com" itemprop="url">www.example.com</a> 
I live in Albuquerque, 標準語彙NM (and 
ボキャブラリー) 
work as an <span itemprop="at <span itemprop="by Bing, affiliation">Google, title">Yahoo! engineer</ACME Corp</and span> 
span>. 
Yandex 
</div> 
• 構造化データをHTMLドキュメントに埋め込むしくみ 
• データを変えることなくドキュメントの構造を変えられる 
• データをURLに結びつけることで、大まかな「データの意 
味」も表す(これもリンクの一種) 
http://getschema.org/index.php/Main_Page
schema.org 
• フィールド名・カラム名は変わるが、標準名は変わらない 
• 変えたときに壊れないように、変わらない基盤としての 
標準と結びつける 
• schema.org はコーポレートスタンダードの1つといえる 
Bing, Google, Yahoo! and Yandex 
• 現在700種類以上のデータタイプを定義
変化に適応するために必要なもの 
data link form 
HTML - ✓ ✓ 
HTML 
+Microdata ✓✓ ✓ ✓ 
• APIには構造化データが必要 
✓✓: 「データの意味」を含む 
• 柔軟なワークフローにはリンクとフォームが必要
HTMLでWeb APIを作ることもできる 
var user = document.getItems('http://schema.org/Person')[0]; 
var name = user.properties['name'][0].itemValue; 
alert('Hello ' + name + '!'); 
• “Microdata DOM API” でHTMLからデータを抽出できる 
http://www.w3.org/TR/microdata/#using-the-microdata-dom-api 
• JavaScriptの実装: https://github.com/termi/Microdata-JS 
• MicrodataからJSONに変換する仕様もいくつかある 
• HTMLはリンクとフォームを持っているのが大きなアドバンテージ
でもきっとJSON Web APIが欲しいはず 
data link form 
HTML 
+Microdata ✓✓ ✓ ✓ 
JSON ✓ - - 
✓✓: 「データの意味」を含む 
• リンクとフォームを埋めればいい 
(できればデータの意味も)
JSONでリンク・フォームを表す 
• リンクやフォームを表 
現できるJSONベースの 
フォーマットを使う 
• 他にも 
Siren, Collection+JSON, 
Mason, Verbose など… 
data link form 
JSON ✓ - - 
JSON 
+Link header ✓ ✓ - 
HAL ✓ ✓ - 
JSON-LD ✓✓ ✓ - 
JSON-LD 
+Hydra ✓✓ ✓ ✓ 
UBER ✓ ✓ ✓ 
✓✓: 「データの意味」を含む
JSONでデータの意味を表す: 
「プロファイル」 
• ALPSプロファイル 
• MicrodataをHTML以外のどんなフォーマットにも適用 
可能にする 
• JSON-LDコンテキスト 
• ドキュメントとコンテキストの両方を同じ1つの 
フォーマットで扱える
A Solution
Hypermicrodata gem 
https://github.com/tkawa/hypermicrodata 
• サーバサイドでHTMLをJSONに変換 
• Microdataだけではなく 
リンクとフォームもHTMLから抽出 
• ベースのALPSプロファイルを用意して、データの意味 
も表しやすい形でJSONベースのフォーマットを生成
class PeopleController < ApplicationController 
before_action :set_message, only: %i(show edit update destroy) 
include Hypermicrodata::Rails::HtmlBasedJsonRenderer 
... 
end 
.person{itemscope: true, itemtype: 'http://schema.org/Person', 
itemid: person_url(@person), data: {main_item: true}} 
.media 
.media-image.pull-left 
= image_tag @person.picture_path, alt: '', itemprop: 'image' 
.media-body 
%h1.media-heading 
%span{itemprop: 'name'}= @person.name 
= link_to 'collection', people_path, rel: 'collection' 
Example in HAL (application/hal+json) 
{ 
"image": "/assets/bob.png", 
"name": "Bob Smith", 
"isPartOf": "/people", 
"_links": { 
"self": { "href": "http://www.example.com/people/1" }, 
"type": { "href": "http://schema.org/Person" }, 
"collection": { "href": "/people" }, 
"profile": { "href": "/assets/person.alps" } 
} 
}
Hypermicrodata gemを使った 
Railsによる設計手順 
1. リソース設計 
2. 状態遷移図を描く 
3. データの名前を対応するURLに結びつける 
4. HTMLテンプレート(Haml, Slimなど)を書いて、Microdata 
でマークアップする 
(その後、必要ならschema.org定義にないプロファイルと説明を書く)
Example: 
Note API
1. リソース設計 
カラム名説明タイプ 
text noteの内容のテキストtext 
published_at noteの公開時間datetime 
(id, created_at, updated_at) (自動生成) 
$ rails g model Note text:text published_at:datetime 
model: Note 
controller: NotesController 
routing: resources :notes
2. 状態遷移図を描く 
Railsの Collection & Member リソースパターンから始める (API ver.) 
item 
collection 
Collection Member 
create*† 
update*, delete* 
* 安全でない 
† 冪等でない
Collection 
of Note 
Note 
(text, published_at, 
created_at, 
updated_at, id) 
item 
collection 
create*† 
update*, delete*, 
publish* 
next, prev 
Home 
notes home 
* 安全でない 
† 冪等でない
3. データの名前を対応するURLに 
結びつける 
Collection of Note http://schema.org/ItemList 
Note http://schema.org/Article 
text http://schema.org/articleBody 
published_at http://schema.org/datePublished 
created_at http://schema.org/dateCreated 
updated_at http://schema.org/dateModified 
id (各noteは個別のURLを持つので不要) 
Home http://schema.org/SiteNavigationElement
item IANA ‘item’ & 
http://schema.org/hasPart 
collection IANA ‘collection’ & 
http://schema.org/isPartOf 
notes - 
create Activity Streams ‘create' 
update Activity Streams ‘update’ 
delete Activity Streams ‘delete’ 
publish Activity Streams ‘post’ 
IANA registered Link Relation: http://www.iana.org/assignments/link-relations/ 
Activity Streams Verbs: http://activitystrea.ms/registry/verbs/
4. HTMLテンプレートとMicrodataを書く 
Collection of Note 
%div{itemscope: true, itemtype: 'http://schema.org/ItemList', 
itemid: notes_url, data: {main_item: true}} 
- @notes.each do |note| 
= link_to note.text.truncate(20), note, 
rel: 'item', itemprop: 'hasPart' 
/app/views/notes/index.html.haml 
GET /notes HTTP/1.1 
Host: www.example.com 
Accept: application/vnd.amundsen-uber+json 
= form_for Note.new do |f| 
= f.text_field :text 
= f.submit rel: 'create' 
{ 
"uber": { 
"version": "1.0", 
"data": [{ 
"url": "http://www.example.com/notes", 
"name": "ItemList", 
"data": [ 
{ "name": "hasPart", "rel": "item", "url": "/notes/1" }, 
{ "name": "hasPart", "rel": "item", "url": "/notes/2" }, 
{ "rel": "create", "url": "/notes", "action": "append", 
"model": "note%5Btext%5D={text}" }, 
{ "rel": "profile", "url": "/assets/note.alps"} 
] 
}] 
} 
} 
Link 
Form
%div{itemscope: true, itemtype: 'http://schema.org/Article', 
itemid: note_url(@note), data: {main_item: true}} 
/app/views/notes/show.html.haml 
%span{itemprop: 'articleBody'}= @note.text 
%span{itemprop: 'datePublished'}= @note.published_at 
%span{itemprop: 'dateCreated'}= @note.created_at 
%span{itemprop: 'dateModified'}= @note.updated_at 
= form_for @note, method: :put do |f| 
= f.text_field :text 
= f.submit rel: 'update' 
= button_to 'Destroy', @note, method: :delete, rel: 'delete' 
= button_to 'Publish', publish_note_path(@note), rel: 'publish' unless @note.published? 
= link_to 'Next note', note_path(@note.next), rel: 'next' if @note.next 
= link_to 'Prev note', note_path(@note.prev), rel: 'prev' if @note.prev 
= link_to 'Collection of Note', notes_path, rel: 'collection', itemprop: 'isPartOf' 
GET /notes/1 HTTP/1.1 
Host: www.example.com 
Accept: application/vnd.amundsen-uber+json 
Note 
{ 
"uber": { 
"version": "1.0", 
"data": [{ 
"url": "http://www.example.com/notes/1", 
"name": "Article", 
"data": [ 
{ "name": "articleBody", "value": "First note's text" }, 
{ "name": "datePublished", "value": null }, 
{ "name": "dateCreated", "value": "2014-09-11T12:00:31+09:00" }, 
{ "name": "dateModified", "value": "2014-09-11T12:00:31+09:00" }, 
{ "name": "isPartOf", "rel": "collection", "url": "/notes" }, 
{ "rel": "update", "url": "/notes/1", "action": "replace", 
"model": "note%5Btext%5D={text}" }, 
{ "rel": "delete", "url": "/notes/1", "action": "remove" }, 
{ "rel": "publish", "url": "/notes/1/publish", "action": "append" }, 
{ "rel": "next", "url": "/notes/2" }, 
{ "rel": "profile", "url": "/assets/note.alps" } 
] 
}] 
} 
}
%div{itemscope: true, itemtype: 'http://schema.org/Article', 
itemid: note_url(@note), data: {main_item: true}} 
%span{itemprop: 'articleBody'}= @note.text 
%span{itemprop: 'datePublished'}= @note.published_at 
%span{itemprop: 'dateCreated'}= @note.created_at 
%span{itemprop: 'dateModified'}= @note.updated_at 
= form_for @note, method: :put do |f| 
= f.text_field :text 
= f.submit rel: 'update' 
= button_to 'Destroy', @note, method: :delete, rel: 'delete' 
= button_to 'Publish', publish_note_path(@note), rel: 'publish' unless @note.published? 
= link_to 'Next note', note_path(@note.next), rel: 'next' if @note.next 
= link_to 'Prev note', note_path(@note.prev), rel: 'prev' if @note.prev 
= link_to 'Collection of Note', notes_path, rel: 'collection', itemprop: 'isPartOf' 
Note 
= button_to 'Publish', publish_note_path(@note), 
= link_to 'Next note', note_path(@note.next), 
= link_to 'Prev note', note_path(@note.prev), 
{ 
"uber": { 
rel: 'publish' unless @note.published? 
rel: 'next' if @note.next 
rel: 'prev' if @note.prev 
"version": "1.0", 
"data": [{ 
"url": "http://www.example.com/notes/1", 
"name": "Article", 
"data": [ 
条件の表現 
publishできるが 
prevには行けない 
{ "name": "articleBody", "value": "First note's text" }, 
{ "name": "datePublished", "value": null }, 
{ "name": "dateCreated", "value": "2014-09-11T12:00:31+09:00" }, 
{ "{ rel": "name": "publish", "dateModified", "url": "value": "/"2014-notes/09-11T12:1/publish", 
00:31+09:00" }, 
"{ action": "name": "isPartOf", "append" "rel": }, 
"collection", "url": "/notes" }, 
{ "rel": "update", "url": "/notes/1", "action": "replace", 
{ "rel": "model": "next", "note%5Btext%"url": 5D={text}" "/notes/}, 
2" }, 
{ "rel": "delete", "url": "/notes/1", "action": "remove" }, 
{ "rel": "publish", "url": "/notes/1/publish", "action": "append" }, 
{ "rel": "next", "url": "/notes/2" }, 
{ "rel": "profile", "url": "/assets/note.alps" } 
] 
}] 
} 
}
この設計手順の 
3つのメリット
メリット 1: DRY 
• リンクとフォームをHTMLテンプレートに一度 
書けば、JSON生成時にも再利用できる 
• Microdataマークアップもそのまま再利用できる 
• Bonus: HTMLのMicrodataはSEO効果を上げる 
(JSONにも可能性あり)
メリット 2: リンクとフォームを 
意識できる 
• JSON Web APIを作るときには、状態遷移の重要 
性を見落としやすい 
• APIをHTMLのWebアプリのように表現すること 
で、状態遷移に着目して適切にリンクとフォー 
ムを実装できる
メリット 3: 制約 
• 「HTMLドキュメントをMicrodataでマークアップし 
て、それを一定のルールでフォーマットされた 
JSONに変換する」という制約 
• この制約はよりよい設計のガイド 
• “Constraints are liberating” 「制約は自由をもたらす」
もしJSONだけを書くときは 
注意すること 
• リンク・フォームを意識するために: 
• 状態遷移図を描きましょう 
• APIを疎結合に保つために: 
• model.to_json の代わりに Jbuilder/RABL のようなビューテンプレートや 
リプレゼンターを使いましょう 
• リンクとフォームを持ったJSONベースのフォーマットを使いましょう 
• さらに schema.org のような標準名を使うとベター
“WebアプリとWeb APIを分けて考えない” 
– 「Webを支える技術」@yohei
結論: Web APIはHTML Webアプリと 
同じように設計しよう 
• Web APIは特別なものではなく、ただ表現 
フォーマットが違うだけ 
• 状態遷移図を描いて状態遷移を意識すること 
で、リンクやフォームを忘れずにすむ
最後に 
• 残念ながら、JSONフォーマット、クライアント実 
装やライブラリにはデファクトスタンダードがない 
• RESTの制約・原則を意識するともっとうまくでき 
る 
• ハイパーメディアはRESTの最も重要な要素の1つで 
変化に適応できるWeb APIへの重要なステップ
よりよい、変化に適応できるWeb APIを作りましょう 
Thank you for your attention. 
References 
• L. Richardson & M. Amundsen “RESTful Web APIs” (O’Reilly) 
• 山本陽平 “Webを支える技術” (技術評論社) 
• Designing for Reuse: Creating APIs for the Future 
http://www.oscon.com/oscon2014/public/schedule/detail/34922 
• API Design Workshop 配布資料 
http://events.layer7tech.com/tokyo-wrk 
• https://speakerdeck.com/zdne/robust-mobile-clients-v2 
• http://www.slideshare.net/yohei/webapi-36871915 
• http://smizell.com/weblog/2014/solving-fizzbuzz-with-hypermedia 
• 山口 徹 “Web API デザインの鉄則” WEB+DB PRESS Vol.82

More Related Content

What's hot

HTML5でオフラインWebアプリケーションを作ろう
HTML5でオフラインWebアプリケーションを作ろうHTML5でオフラインWebアプリケーションを作ろう
HTML5でオフラインWebアプリケーションを作ろうyoshikawa_t
 
Webフロントエンド開発の最新トレンド - HTML5, モバイル, オフライン
Webフロントエンド開発の最新トレンド - HTML5, モバイル, オフラインWebフロントエンド開発の最新トレンド - HTML5, モバイル, オフライン
Webフロントエンド開発の最新トレンド - HTML5, モバイル, オフラインShumpei Shiraishi
 
マークアップ講座 01b HTML
マークアップ講座 01b HTMLマークアップ講座 01b HTML
マークアップ講座 01b HTMLeiji sekiya
 
JAX-RS(LT)
JAX-RS(LT)JAX-RS(LT)
JAX-RS(LT)winplus
 
WordPress実践 導入からカスタマイズまで
WordPress実践 導入からカスタマイズまでWordPress実践 導入からカスタマイズまで
WordPress実践 導入からカスタマイズまでTakashi Uemura
 
初めての REST - Representational State Transfer
初めての REST - Representational State Transfer初めての REST - Representational State Transfer
初めての REST - Representational State TransferTatsumi Naganuma
 
HTML5マークアップの心得と作法
HTML5マークアップの心得と作法HTML5マークアップの心得と作法
HTML5マークアップの心得と作法Futomi Hatano
 
HTML仕様書を読んでみよう
HTML仕様書を読んでみようHTML仕様書を読んでみよう
HTML仕様書を読んでみようSaeki Tominaga
 
Webapp startup example_to_dolist
Webapp startup example_to_dolistWebapp startup example_to_dolist
Webapp startup example_to_dolistShinichiro Kumeuchi
 
今からハジメるHTML5プログラミング
今からハジメるHTML5プログラミング今からハジメるHTML5プログラミング
今からハジメるHTML5プログラミングSwapSkills
 
今からハジメるHTML5マークアップ
今からハジメるHTML5マークアップ今からハジメるHTML5マークアップ
今からハジメるHTML5マークアップSwapSkills
 
これからHTML5を書く人のためのセキュリティ - HTML5など勉強会
これからHTML5を書く人のためのセキュリティ - HTML5など勉強会これからHTML5を書く人のためのセキュリティ - HTML5など勉強会
これからHTML5を書く人のためのセキュリティ - HTML5など勉強会yoshinori matsumoto
 
情報編集(Web) HTML5とは何か? HTML5、はじめの一歩
情報編集(Web)  HTML5とは何か? HTML5、はじめの一歩情報編集(Web)  HTML5とは何か? HTML5、はじめの一歩
情報編集(Web) HTML5とは何か? HTML5、はじめの一歩Atsushi Tadokoro
 
HTML/CSS/JS基础
HTML/CSS/JS基础HTML/CSS/JS基础
HTML/CSS/JS基础jay li
 

What's hot (20)

HTML5でオフラインWebアプリケーションを作ろう
HTML5でオフラインWebアプリケーションを作ろうHTML5でオフラインWebアプリケーションを作ろう
HTML5でオフラインWebアプリケーションを作ろう
 
Webフロントエンド開発の最新トレンド - HTML5, モバイル, オフライン
Webフロントエンド開発の最新トレンド - HTML5, モバイル, オフラインWebフロントエンド開発の最新トレンド - HTML5, モバイル, オフライン
Webフロントエンド開発の最新トレンド - HTML5, モバイル, オフライン
 
マークアップ講座 01b HTML
マークアップ講座 01b HTMLマークアップ講座 01b HTML
マークアップ講座 01b HTML
 
Chatterを使ったカスタムソーシャル
Chatterを使ったカスタムソーシャルChatterを使ったカスタムソーシャル
Chatterを使ったカスタムソーシャル
 
JAX-RS(LT)
JAX-RS(LT)JAX-RS(LT)
JAX-RS(LT)
 
WordPress実践 導入からカスタマイズまで
WordPress実践 導入からカスタマイズまでWordPress実践 導入からカスタマイズまで
WordPress実践 導入からカスタマイズまで
 
初めての REST - Representational State Transfer
初めての REST - Representational State Transfer初めての REST - Representational State Transfer
初めての REST - Representational State Transfer
 
HTML5マークアップの心得と作法
HTML5マークアップの心得と作法HTML5マークアップの心得と作法
HTML5マークアップの心得と作法
 
Web Intents入門
Web Intents入門Web Intents入門
Web Intents入門
 
HTML5, きちんと。
HTML5, きちんと。HTML5, きちんと。
HTML5, きちんと。
 
HTML仕様書を読んでみよう
HTML仕様書を読んでみようHTML仕様書を読んでみよう
HTML仕様書を読んでみよう
 
Webapp startup example_to_dolist
Webapp startup example_to_dolistWebapp startup example_to_dolist
Webapp startup example_to_dolist
 
The new Text::Hatena
The new Text::HatenaThe new Text::Hatena
The new Text::Hatena
 
今からハジメるHTML5プログラミング
今からハジメるHTML5プログラミング今からハジメるHTML5プログラミング
今からハジメるHTML5プログラミング
 
今からハジメるHTML5マークアップ
今からハジメるHTML5マークアップ今からハジメるHTML5マークアップ
今からハジメるHTML5マークアップ
 
これからHTML5を書く人のためのセキュリティ - HTML5など勉強会
これからHTML5を書く人のためのセキュリティ - HTML5など勉強会これからHTML5を書く人のためのセキュリティ - HTML5など勉強会
これからHTML5を書く人のためのセキュリティ - HTML5など勉強会
 
情報編集(Web) HTML5とは何か? HTML5、はじめの一歩
情報編集(Web)  HTML5とは何か? HTML5、はじめの一歩情報編集(Web)  HTML5とは何か? HTML5、はじめの一歩
情報編集(Web) HTML5とは何か? HTML5、はじめの一歩
 
HTML/CSS/JS基础
HTML/CSS/JS基础HTML/CSS/JS基础
HTML/CSS/JS基础
 
勉強会資料①
勉強会資料①勉強会資料①
勉強会資料①
 
Swift + JSON via WordPress
Swift + JSON via WordPressSwift + JSON via WordPress
Swift + JSON via WordPress
 

Viewers also liked

Rails Gems realize RESTful modeling patterns
Rails Gems realize RESTful modeling patternsRails Gems realize RESTful modeling patterns
Rails Gems realize RESTful modeling patternsToru Kawamura
 
RESTful Meetup vol.3 Introduction
RESTful Meetup vol.3 IntroductionRESTful Meetup vol.3 Introduction
RESTful Meetup vol.3 IntroductionToru Kawamura
 
Hypermedia: The Missing Element to Building Adaptable Web APIs in Rails
Hypermedia: The Missing Element to Building Adaptable Web APIs in RailsHypermedia: The Missing Element to Building Adaptable Web APIs in Rails
Hypermedia: The Missing Element to Building Adaptable Web APIs in RailsToru Kawamura
 
Web Clients for Ruby and What they should be in the future
Web Clients for Ruby and What they should be in the futureWeb Clients for Ruby and What they should be in the future
Web Clients for Ruby and What they should be in the futureToru Kawamura
 
ഒരു അണ്‍സര്‍വ്വേ പ്രദേശത്തെ ഭൂപടനിര്‍മ്മാണപരിശ്രമം - കൂരാച്ചുണ്ടു് ഗ്രാമപഞ്ചാ...
ഒരു അണ്‍സര്‍വ്വേ പ്രദേശത്തെ ഭൂപടനിര്‍മ്മാണപരിശ്രമം - കൂരാച്ചുണ്ടു് ഗ്രാമപഞ്ചാ...ഒരു അണ്‍സര്‍വ്വേ പ്രദേശത്തെ ഭൂപടനിര്‍മ്മാണപരിശ്രമം - കൂരാച്ചുണ്ടു് ഗ്രാമപഞ്ചാ...
ഒരു അണ്‍സര്‍വ്വേ പ്രദേശത്തെ ഭൂപടനിര്‍മ്മാണപരിശ്രമം - കൂരാച്ചുണ്ടു് ഗ്രാമപഞ്ചാ...Jaisen Nedumpala
 
Trabajo colaborativo list
Trabajo colaborativo listTrabajo colaborativo list
Trabajo colaborativo listKaterin Colcha
 
Sul sentiero dell’emozioni lezioned el 4 aprile 2012
Sul sentiero dell’emozioni lezioned el 4 aprile 2012Sul sentiero dell’emozioni lezioned el 4 aprile 2012
Sul sentiero dell’emozioni lezioned el 4 aprile 2012melogranoverde
 
Understanding Product/Market Fit
Understanding Product/Market FitUnderstanding Product/Market Fit
Understanding Product/Market FitGabor Papp
 
Gem 1
Gem 1Gem 1
Gem 1bfnd
 
Unityを使ったVRアプリ作成入門 ABCD2015金沢編
Unityを使ったVRアプリ作成入門 ABCD2015金沢編Unityを使ったVRアプリ作成入門 ABCD2015金沢編
Unityを使ったVRアプリ作成入門 ABCD2015金沢編kinneko
 
CloudSurance - We backup web application data
CloudSurance - We backup web application dataCloudSurance - We backup web application data
CloudSurance - We backup web application dataSam Bowen
 
這一打‧好貴
這一打‧好貴這一打‧好貴
這一打‧好貴fudy9015
 
AOA - Annual OMEL Conference Encourages Osteopathic Discourse
AOA - Annual OMEL Conference Encourages Osteopathic Discourse AOA - Annual OMEL Conference Encourages Osteopathic Discourse
AOA - Annual OMEL Conference Encourages Osteopathic Discourse Dr. Michael Thomas (Neurosurgeon)
 
Roxana Ivan - Buget mic pentru evenimente mari (Impact Hub Bucharest, 2014.02...
Roxana Ivan - Buget mic pentru evenimente mari (Impact Hub Bucharest, 2014.02...Roxana Ivan - Buget mic pentru evenimente mari (Impact Hub Bucharest, 2014.02...
Roxana Ivan - Buget mic pentru evenimente mari (Impact Hub Bucharest, 2014.02...Lumea SEO PPC
 
Videómarketing szállodáknak
Videómarketing szállodáknakVideómarketing szállodáknak
Videómarketing szállodáknakTamás A.
 
The power of abstraction
The power of abstractionThe power of abstraction
The power of abstractionACMBangalore
 

Viewers also liked (20)

Rails Gems realize RESTful modeling patterns
Rails Gems realize RESTful modeling patternsRails Gems realize RESTful modeling patterns
Rails Gems realize RESTful modeling patterns
 
RESTful Meetup vol.3 Introduction
RESTful Meetup vol.3 IntroductionRESTful Meetup vol.3 Introduction
RESTful Meetup vol.3 Introduction
 
Hypermedia: The Missing Element to Building Adaptable Web APIs in Rails
Hypermedia: The Missing Element to Building Adaptable Web APIs in RailsHypermedia: The Missing Element to Building Adaptable Web APIs in Rails
Hypermedia: The Missing Element to Building Adaptable Web APIs in Rails
 
Web API入門
Web API入門Web API入門
Web API入門
 
Rest ful api設計入門
Rest ful api設計入門Rest ful api設計入門
Rest ful api設計入門
 
Web Clients for Ruby and What they should be in the future
Web Clients for Ruby and What they should be in the futureWeb Clients for Ruby and What they should be in the future
Web Clients for Ruby and What they should be in the future
 
ഒരു അണ്‍സര്‍വ്വേ പ്രദേശത്തെ ഭൂപടനിര്‍മ്മാണപരിശ്രമം - കൂരാച്ചുണ്ടു് ഗ്രാമപഞ്ചാ...
ഒരു അണ്‍സര്‍വ്വേ പ്രദേശത്തെ ഭൂപടനിര്‍മ്മാണപരിശ്രമം - കൂരാച്ചുണ്ടു് ഗ്രാമപഞ്ചാ...ഒരു അണ്‍സര്‍വ്വേ പ്രദേശത്തെ ഭൂപടനിര്‍മ്മാണപരിശ്രമം - കൂരാച്ചുണ്ടു് ഗ്രാമപഞ്ചാ...
ഒരു അണ്‍സര്‍വ്വേ പ്രദേശത്തെ ഭൂപടനിര്‍മ്മാണപരിശ്രമം - കൂരാച്ചുണ്ടു് ഗ്രാമപഞ്ചാ...
 
Trabajo colaborativo list
Trabajo colaborativo listTrabajo colaborativo list
Trabajo colaborativo list
 
Sul sentiero dell’emozioni lezioned el 4 aprile 2012
Sul sentiero dell’emozioni lezioned el 4 aprile 2012Sul sentiero dell’emozioni lezioned el 4 aprile 2012
Sul sentiero dell’emozioni lezioned el 4 aprile 2012
 
Understanding Product/Market Fit
Understanding Product/Market FitUnderstanding Product/Market Fit
Understanding Product/Market Fit
 
Gem 1
Gem 1Gem 1
Gem 1
 
Unityを使ったVRアプリ作成入門 ABCD2015金沢編
Unityを使ったVRアプリ作成入門 ABCD2015金沢編Unityを使ったVRアプリ作成入門 ABCD2015金沢編
Unityを使ったVRアプリ作成入門 ABCD2015金沢編
 
CloudSurance - We backup web application data
CloudSurance - We backup web application dataCloudSurance - We backup web application data
CloudSurance - We backup web application data
 
這一打‧好貴
這一打‧好貴這一打‧好貴
這一打‧好貴
 
I16092.00_E501-E501
I16092.00_E501-E501I16092.00_E501-E501
I16092.00_E501-E501
 
AOA - Annual OMEL Conference Encourages Osteopathic Discourse
AOA - Annual OMEL Conference Encourages Osteopathic Discourse AOA - Annual OMEL Conference Encourages Osteopathic Discourse
AOA - Annual OMEL Conference Encourages Osteopathic Discourse
 
Roxana Ivan - Buget mic pentru evenimente mari (Impact Hub Bucharest, 2014.02...
Roxana Ivan - Buget mic pentru evenimente mari (Impact Hub Bucharest, 2014.02...Roxana Ivan - Buget mic pentru evenimente mari (Impact Hub Bucharest, 2014.02...
Roxana Ivan - Buget mic pentru evenimente mari (Impact Hub Bucharest, 2014.02...
 
Videómarketing szállodáknak
Videómarketing szállodáknakVideómarketing szállodáknak
Videómarketing szállodáknak
 
Govt
GovtGovt
Govt
 
The power of abstraction
The power of abstractionThe power of abstraction
The power of abstraction
 

Similar to Hypermedia: The Missing Element to Building Adaptable Web APIs in Rails (増補日本語版)

Azure でサーバーレス、 Infrastructure as Code どうしてますか?
Azure でサーバーレス、 Infrastructure as Code どうしてますか?Azure でサーバーレス、 Infrastructure as Code どうしてますか?
Azure でサーバーレス、 Infrastructure as Code どうしてますか?Kazumi IWANAGA
 
Elixir入門「第3回:Phoenix 1.2で高速Webアプリ & REST APIをサクッと書いてみる」【旧版】※新版あります
Elixir入門「第3回:Phoenix 1.2で高速Webアプリ & REST APIをサクッと書いてみる」【旧版】※新版ありますElixir入門「第3回:Phoenix 1.2で高速Webアプリ & REST APIをサクッと書いてみる」【旧版】※新版あります
Elixir入門「第3回:Phoenix 1.2で高速Webアプリ & REST APIをサクッと書いてみる」【旧版】※新版ありますfukuoka.ex
 
Concentrated HTML5 & Attractive HTML5
Concentrated HTML5 & Attractive HTML5Concentrated HTML5 & Attractive HTML5
Concentrated HTML5 & Attractive HTML5Sho Ito
 
ASP.NET シングル ページ アプリケーション (SPA) 詳説
ASP.NET シングル ページ アプリケーション (SPA) 詳説ASP.NET シングル ページ アプリケーション (SPA) 詳説
ASP.NET シングル ページ アプリケーション (SPA) 詳説Akira Inoue
 
オフラインファーストの思想と実践
オフラインファーストの思想と実践オフラインファーストの思想と実践
オフラインファーストの思想と実践Shumpei Shiraishi
 
WordPress APIで作るモバイルアプリ
WordPress APIで作るモバイルアプリWordPress APIで作るモバイルアプリ
WordPress APIで作るモバイルアプリアシアル株式会社
 
未来のwebに欠かせないREST APIをApache Solr + Drupal8で実装しよう@PHPカンファレンス2016 東京
未来のwebに欠かせないREST APIをApache Solr + Drupal8で実装しよう@PHPカンファレンス2016 東京未来のwebに欠かせないREST APIをApache Solr + Drupal8で実装しよう@PHPカンファレンス2016 東京
未来のwebに欠かせないREST APIをApache Solr + Drupal8で実装しよう@PHPカンファレンス2016 東京Masayuki Abe
 
WebIDLを見てみる
WebIDLを見てみるWebIDLを見てみる
WebIDLを見てみるtakenspc
 
Rubyで作るtwitter風webアプリケーション
Rubyで作るtwitter風webアプリケーションRubyで作るtwitter風webアプリケーション
Rubyで作るtwitter風webアプリケーションNaoto Hori
 
Elixir入門「第3回:Phoenix 1.3で高速webアプリ & REST APIアプリをサクッと書いてみる」
Elixir入門「第3回:Phoenix 1.3で高速webアプリ & REST APIアプリをサクッと書いてみる」Elixir入門「第3回:Phoenix 1.3で高速webアプリ & REST APIアプリをサクッと書いてみる」
Elixir入門「第3回:Phoenix 1.3で高速webアプリ & REST APIアプリをサクッと書いてみる」fukuoka.ex
 
ASP.NET Core WebAPIでODataを使おう
ASP.NET Core WebAPIでODataを使おうASP.NET Core WebAPIでODataを使おう
ASP.NET Core WebAPIでODataを使おうDevTakas
 
Web API(Dynamics 365 )勉強会
Web API(Dynamics 365 )勉強会Web API(Dynamics 365 )勉強会
Web API(Dynamics 365 )勉強会Kazuya Sugimoto
 
Apps for office オンプレミスとクラウド
Apps for office オンプレミスとクラウドApps for office オンプレミスとクラウド
Apps for office オンプレミスとクラウドHirotada Watanabe
 
Spring data-rest-and-spring-cloud-contract
Spring data-rest-and-spring-cloud-contractSpring data-rest-and-spring-cloud-contract
Spring data-rest-and-spring-cloud-contractTakeshi Ogawa
 
SilverlightとSharePoint2010の紹介
SilverlightとSharePoint2010の紹介SilverlightとSharePoint2010の紹介
SilverlightとSharePoint2010の紹介Tadahiro Higuchi
 
TokyoWebminig カジュアルなHadoop
TokyoWebminig カジュアルなHadoopTokyoWebminig カジュアルなHadoop
TokyoWebminig カジュアルなHadoopTeruo Kawasaki
 

Similar to Hypermedia: The Missing Element to Building Adaptable Web APIs in Rails (増補日本語版) (20)

Azure でサーバーレス、 Infrastructure as Code どうしてますか?
Azure でサーバーレス、 Infrastructure as Code どうしてますか?Azure でサーバーレス、 Infrastructure as Code どうしてますか?
Azure でサーバーレス、 Infrastructure as Code どうしてますか?
 
Connect with Data API
Connect with Data APIConnect with Data API
Connect with Data API
 
Elixir入門「第3回:Phoenix 1.2で高速Webアプリ & REST APIをサクッと書いてみる」【旧版】※新版あります
Elixir入門「第3回:Phoenix 1.2で高速Webアプリ & REST APIをサクッと書いてみる」【旧版】※新版ありますElixir入門「第3回:Phoenix 1.2で高速Webアプリ & REST APIをサクッと書いてみる」【旧版】※新版あります
Elixir入門「第3回:Phoenix 1.2で高速Webアプリ & REST APIをサクッと書いてみる」【旧版】※新版あります
 
Concentrated HTML5 & Attractive HTML5
Concentrated HTML5 & Attractive HTML5Concentrated HTML5 & Attractive HTML5
Concentrated HTML5 & Attractive HTML5
 
ASP.NET シングル ページ アプリケーション (SPA) 詳説
ASP.NET シングル ページ アプリケーション (SPA) 詳説ASP.NET シングル ページ アプリケーション (SPA) 詳説
ASP.NET シングル ページ アプリケーション (SPA) 詳説
 
APIMeetup 20170329_ichimura
APIMeetup 20170329_ichimuraAPIMeetup 20170329_ichimura
APIMeetup 20170329_ichimura
 
オフラインファーストの思想と実践
オフラインファーストの思想と実践オフラインファーストの思想と実践
オフラインファーストの思想と実践
 
WordPress APIで作るモバイルアプリ
WordPress APIで作るモバイルアプリWordPress APIで作るモバイルアプリ
WordPress APIで作るモバイルアプリ
 
未来のwebに欠かせないREST APIをApache Solr + Drupal8で実装しよう@PHPカンファレンス2016 東京
未来のwebに欠かせないREST APIをApache Solr + Drupal8で実装しよう@PHPカンファレンス2016 東京未来のwebに欠かせないREST APIをApache Solr + Drupal8で実装しよう@PHPカンファレンス2016 東京
未来のwebに欠かせないREST APIをApache Solr + Drupal8で実装しよう@PHPカンファレンス2016 東京
 
WebIDLを見てみる
WebIDLを見てみるWebIDLを見てみる
WebIDLを見てみる
 
Rubyで作るtwitter風webアプリケーション
Rubyで作るtwitter風webアプリケーションRubyで作るtwitter風webアプリケーション
Rubyで作るtwitter風webアプリケーション
 
Elixir入門「第3回:Phoenix 1.3で高速webアプリ & REST APIアプリをサクッと書いてみる」
Elixir入門「第3回:Phoenix 1.3で高速webアプリ & REST APIアプリをサクッと書いてみる」Elixir入門「第3回:Phoenix 1.3で高速webアプリ & REST APIアプリをサクッと書いてみる」
Elixir入門「第3回:Phoenix 1.3で高速webアプリ & REST APIアプリをサクッと書いてみる」
 
ASP.NET Core WebAPIでODataを使おう
ASP.NET Core WebAPIでODataを使おうASP.NET Core WebAPIでODataを使おう
ASP.NET Core WebAPIでODataを使おう
 
Web API(Dynamics 365 )勉強会
Web API(Dynamics 365 )勉強会Web API(Dynamics 365 )勉強会
Web API(Dynamics 365 )勉強会
 
Apps for office オンプレミスとクラウド
Apps for office オンプレミスとクラウドApps for office オンプレミスとクラウド
Apps for office オンプレミスとクラウド
 
UnicastWS vol.2
UnicastWS vol.2UnicastWS vol.2
UnicastWS vol.2
 
AWS小ネタ集
AWS小ネタ集AWS小ネタ集
AWS小ネタ集
 
Spring data-rest-and-spring-cloud-contract
Spring data-rest-and-spring-cloud-contractSpring data-rest-and-spring-cloud-contract
Spring data-rest-and-spring-cloud-contract
 
SilverlightとSharePoint2010の紹介
SilverlightとSharePoint2010の紹介SilverlightとSharePoint2010の紹介
SilverlightとSharePoint2010の紹介
 
TokyoWebminig カジュアルなHadoop
TokyoWebminig カジュアルなHadoopTokyoWebminig カジュアルなHadoop
TokyoWebminig カジュアルなHadoop
 

More from Toru Kawamura

RailsスタイルからRESTを学ぼう よちがや.rb
RailsスタイルからRESTを学ぼう よちがや.rbRailsスタイルからRESTを学ぼう よちがや.rb
RailsスタイルからRESTを学ぼう よちがや.rbToru Kawamura
 
リソースモデリングパターンの提案 #sendagayarb
リソースモデリングパターンの提案 #sendagayarbリソースモデリングパターンの提案 #sendagayarb
リソースモデリングパターンの提案 #sendagayarbToru Kawamura
 
routes.rb をもう一度考えてみた #shibuyarb
routes.rb をもう一度考えてみた #shibuyarbroutes.rb をもう一度考えてみた #shibuyarb
routes.rb をもう一度考えてみた #shibuyarbToru Kawamura
 
返信と@ツイートの仕様変更と提案 #twtr_hack
返信と@ツイートの仕様変更と提案 #twtr_hack返信と@ツイートの仕様変更と提案 #twtr_hack
返信と@ツイートの仕様変更と提案 #twtr_hackToru Kawamura
 
RESTとRailsスタイル
RESTとRailsスタイルRESTとRailsスタイル
RESTとRailsスタイルToru Kawamura
 
OAuth Echo の Rails Gem
OAuth Echo の Rails GemOAuth Echo の Rails Gem
OAuth Echo の Rails GemToru Kawamura
 

More from Toru Kawamura (7)

真のREST
真のREST真のREST
真のREST
 
RailsスタイルからRESTを学ぼう よちがや.rb
RailsスタイルからRESTを学ぼう よちがや.rbRailsスタイルからRESTを学ぼう よちがや.rb
RailsスタイルからRESTを学ぼう よちがや.rb
 
リソースモデリングパターンの提案 #sendagayarb
リソースモデリングパターンの提案 #sendagayarbリソースモデリングパターンの提案 #sendagayarb
リソースモデリングパターンの提案 #sendagayarb
 
routes.rb をもう一度考えてみた #shibuyarb
routes.rb をもう一度考えてみた #shibuyarbroutes.rb をもう一度考えてみた #shibuyarb
routes.rb をもう一度考えてみた #shibuyarb
 
返信と@ツイートの仕様変更と提案 #twtr_hack
返信と@ツイートの仕様変更と提案 #twtr_hack返信と@ツイートの仕様変更と提案 #twtr_hack
返信と@ツイートの仕様変更と提案 #twtr_hack
 
RESTとRailsスタイル
RESTとRailsスタイルRESTとRailsスタイル
RESTとRailsスタイル
 
OAuth Echo の Rails Gem
OAuth Echo の Rails GemOAuth Echo の Rails Gem
OAuth Echo の Rails Gem
 

Recently uploaded

論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A surveyToru Tamaki
 
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略Ryo Sasaki
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Yuma Ohgami
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...Toru Tamaki
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNetToru Tamaki
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdftaisei2219
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムsugiuralab
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものですiPride Co., Ltd.
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)Hiroki Ichikura
 

Recently uploaded (9)

論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey
 
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdf
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システム
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものです
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
 

Hypermedia: The Missing Element to Building Adaptable Web APIs in Rails (増補日本語版)

  • 1. HYPERMEDIA: THE MISSING ELEMENT to Building Adaptable Web APIs in Rails ハイパーメディア: RailsでWeb APIをつくるには、これが足りない Toru Kawamura @tkawa ! RubyKaigi 2014 RESTful Web APIs 読書会 #19 2014.10.09
  • 2. @tkawa Toru Kawamura • フリーランス Ruby/Rails プログラマ • Technology Assistance Partner at SonicGarden Inc. • REST厨 (RESTafarian) inspired by Yohei Yamamoto (@yohei) • Sendagaya.rb 共同主催 • “RESTful Web APIs” 読書会主催
  • 7. • プライベート • 内部から使われる • SPAや専用の クライアントが使う • だいたい予想できる コントロールできる • パブリック • 外部から使われる • 汎用的な目的の クライアントが使う • 予想しづらい コントロールしづらい
  • 8. – 「WebAPIのこれまでとこれから」by @yohei http://www.slideshare.net/yohei/webapi-36871915
  • 11. 変化は避けられない ! Web APIは変化に適応しなければならない
  • 12. 2種類の Change バージョンが変わるバージョンが変わらない 互換性がない互換性がある クライアントを壊すクライアントを壊さない
  • 13. 2種類の Change バージョンが変わるバージョンが変わらない 互換性がない互換性がある クライアントを壊すクライアントを壊さない 壊す Change 壊さない Change
  • 14. 壊すChangeはよくない • ひどいユーザ体験を生む • クライアント開発者にコードの書き直し・ 再デプロイを強いる • もし     だったら…
  • 15. なぜ起こる? バージョンが変わるバージョンが変わらない 互換性がない互換性がある クライアントを壊すクライアントを壊さない 壊す Change 壊さない Change
  • 17. GET /v2/statuses/#{id} GET /v1/statuses?id=#{id} ×コードの書き直しが必要
  • 18. 機械が読める説明書から作られる クライアントもある { "apiVersion": "1.0.0", "basePath": "http:// petstore.swagger.wordnik.com/api", "resourcePath": "/store", "produces": [ "application/json" ], "apis": [ { "path": "/store/order/{orderId}", "operations": [ { GET /v1/statuses?id=#{id} GET /v1/statuses?id=#{id} "method": "GET", "summary": "Find purchase order by ID", "notes": "For valid response try integer IDs with value <= 5. Anything above 5 or nonintegers will generate API errors", "type": "Order", "nickname": "getOrderById", "authorizations": {}, "parameters": [
  • 19. GET /v2/statuses/#{id} GET /v1/statuses?id=#{id} ×コードの再生成が必要 { "apiVersion": "2.0.0", "basePath": "http:// petstore.swagger.wordnik.com/api", "resourcePath": "/store", "produces": [ "application/json" ], "apis": [ { "path": "/store/order/{orderId}", "operations": [ { "method": "GET", "summary": "Find purchase order by ID", "notes": "For valid response try integer IDs with value <= 5. Anything above 5 or nonintegers will generate API errors", "type": "Order", "nickname": "getOrderById", "authorizations": {}, "parameters": [
  • 20. { uber: { version: "1.0", data: [{ url: "http://www.ishuran.dev/notes/1", name: "Article", data: [ { name: "articleBody", value: "First note's text" }, { name: "datePublished", value: null }, { name: "dateCreated", value: "2014-09-11T12:00:31+09:00" }, { name: "dateModified", value: "2014-09-11T12:00:31+09:00" }, { name: "isPartOf", rel: "collection", url: "/notes"
  • 21. { uber: { 「密結合」が原因 version: "1.0", data: [{ url: "http://www.ishuran.dev/notes/1", name: "Article", data: [ • APIの変更がクライアントに反映されればよい { name: "articleBody", value: "First note's text" }, { name: "datePublished", value: null }, { name: "dateCreated", value: "2014-09-11T12:00:31+09:00" }, { name: "dateModified", value: "2014-09-11T12:00:31+09:00" }, { name: "isPartOf", rel: "collection", url: "/notes" • APIの説明を分割して各レスポンスに埋め込む のが良い方法 • APIについての多大な仮定は密結合を生む
  • 23. 例で見る疎結合: FizzBuzzaaS • by Stephen Mizell http://fizzbuzzaas.herokuapp.com/ http://smizell.com/weblog/2014/solving-fizzbuzz-with-hypermedia • サーバは与えられた100までの数の FizzBuzzを計算できる • サーバは次のFizzBuzzが何になるか知っ ている • クライアントは1から最後まで順番にす http://sef.kloninger.com/posts/ べてのFizzBuzzが欲しい 201205fizzbuzz-for-managers. html
  • 24. 密結合なクライアント answer = HTTP.get("/v1/fizzbuzz?number=#{i}") puts answer end "/v2/fizzbuzz/#{i}" (1..1000) (1..100).each do |i| • すべてのURLとパラメータがハードコードされている • カウントアップのような、サーバロジックと同じこと をクライアントでも行っている
  • 25. 疎結合なクライアント root = HTTP.get_root answer = root.link('first').follow puts answer while answer.link('next').present? answer = answer.link('next').follow puts answer end next リンクが重要 • ハードコードされたURLなし • URLや条件を変えてもクライアントは壊れ ない
  • 26. • 実際にリンクをたど る代わりに、 埋め込みリソースを 使うことで リクエスト数を減ら すことが可能 http://techlife.cookpad.com/entry/2014/09/08/093000
  • 27. 「APIコール」のメタファーは危険 • クライアントがあらかじめURLとパラメータを用意 してAPIを呼ぶ、というRPCのようなパラダイムから 離れよう • クライアントが次にすることは、レスポンスの中の リンクから選ぶこと == ハイパーメディア
  • 29. HTMLのWeb • WebアプリやWebサイ トはずっと変わり続け ているが、ブラウザは 壊れていない • HTMLのWebでは、なぜ HTMLのリンクブラウザは壊れない? http://www.youtypeitwepostit.com/messages
  • 30. HTMLの中のデータ • HTMLが表現する意味は 「ヒューマンリーダブルなドキュメント」 • 段落、リスト、表、セクション、… • これが人間にゆるく伝わればよい
  • 31. HTMLの中のワークフロー • Webアプリはワークフ ロー(の提案)を含む • ワークフローは一連の 画面遷移で表現される — リンク と フォーム ”RESTful Web APIs” p.11 Figure 1-7
  • 32. ハイパーメディアはワークフローを示す • 各画面は次に何ができる かの「メニュー」としてリ ンクやフォームを含む • ブラウザはその「メニュー」 の中から選んで次へ進む • これがハイパーメディア で、FizzBuzzaaSもやってい たこと 3 4
  • 33. もしHTMLにリンクがなかったら? 代わりにワークフロー手順書がある? • 各WebアプリごとにURLやパラ メータをハードコードした専用 クライアントを作りたくなる • クライアントとサーバのコード が密結合して、変更できない Webアプリになってしまう • これが今のWeb APIがやってい ること メッセージWebアプリ利用の手順書 1. アドレスバーに /messages と入力し て GET 2. アドレスは /messages のまま、 title と body のパラメータに文字列を セットして POST 3. message-id を受け取って、アドレス バーに /messages/{message-id} と入 力して GET
  • 34. クローラにはもう1つヒントが • クローラはリンクをたどる(submitできるフォームもある) • クローラはHTMLドキュメントの中にあるデータと その「意味」を理解している • どうやって? https://support.google.com/webmasters/answer/99170
  • 36. Microdata <div itemscope itemtype="http://schema.org/Person"> My name is <span itemprop="name">Bob Smith</span> but people call me <span itemprop="nickname">Smithy</span>. Here is my home page: <a href="http://www.example.com" itemprop="url">www.example.com</a> I live in Albuquerque, NM and work as an <span itemprop="title">engineer</span> at <span itemprop="affiliation">ACME Corp</span>. </div> • 構造化データをHTMLドキュメントに埋め込むしくみ • データを変えることなくドキュメントの構造を変えられる • データをURLに結びつけることで、大まかな「データの意 味」も表す(これもリンクの一種)
  • 37. Microdata <div itemscope itemtype="http://schema.org/Person"> My name is <span itemprop="name">Bob Smith</span> but people call me <span schema.itemprop="org nickname">Smithy</span>. Here is my home page: <a href="http://www.example.com" itemprop="url">www.example.com</a> I live in Albuquerque, 標準語彙NM (and ボキャブラリー) work as an <span itemprop="at <span itemprop="by Bing, affiliation">Google, title">Yahoo! engineer</ACME Corp</and span> span>. Yandex </div> • 構造化データをHTMLドキュメントに埋め込むしくみ • データを変えることなくドキュメントの構造を変えられる • データをURLに結びつけることで、大まかな「データの意 味」も表す(これもリンクの一種) http://getschema.org/index.php/Main_Page
  • 38. schema.org • フィールド名・カラム名は変わるが、標準名は変わらない • 変えたときに壊れないように、変わらない基盤としての 標準と結びつける • schema.org はコーポレートスタンダードの1つといえる Bing, Google, Yahoo! and Yandex • 現在700種類以上のデータタイプを定義
  • 39. 変化に適応するために必要なもの data link form HTML - ✓ ✓ HTML +Microdata ✓✓ ✓ ✓ • APIには構造化データが必要 ✓✓: 「データの意味」を含む • 柔軟なワークフローにはリンクとフォームが必要
  • 40. HTMLでWeb APIを作ることもできる var user = document.getItems('http://schema.org/Person')[0]; var name = user.properties['name'][0].itemValue; alert('Hello ' + name + '!'); • “Microdata DOM API” でHTMLからデータを抽出できる http://www.w3.org/TR/microdata/#using-the-microdata-dom-api • JavaScriptの実装: https://github.com/termi/Microdata-JS • MicrodataからJSONに変換する仕様もいくつかある • HTMLはリンクとフォームを持っているのが大きなアドバンテージ
  • 41. でもきっとJSON Web APIが欲しいはず data link form HTML +Microdata ✓✓ ✓ ✓ JSON ✓ - - ✓✓: 「データの意味」を含む • リンクとフォームを埋めればいい (できればデータの意味も)
  • 42. JSONでリンク・フォームを表す • リンクやフォームを表 現できるJSONベースの フォーマットを使う • 他にも Siren, Collection+JSON, Mason, Verbose など… data link form JSON ✓ - - JSON +Link header ✓ ✓ - HAL ✓ ✓ - JSON-LD ✓✓ ✓ - JSON-LD +Hydra ✓✓ ✓ ✓ UBER ✓ ✓ ✓ ✓✓: 「データの意味」を含む
  • 43. JSONでデータの意味を表す: 「プロファイル」 • ALPSプロファイル • MicrodataをHTML以外のどんなフォーマットにも適用 可能にする • JSON-LDコンテキスト • ドキュメントとコンテキストの両方を同じ1つの フォーマットで扱える
  • 45. Hypermicrodata gem https://github.com/tkawa/hypermicrodata • サーバサイドでHTMLをJSONに変換 • Microdataだけではなく リンクとフォームもHTMLから抽出 • ベースのALPSプロファイルを用意して、データの意味 も表しやすい形でJSONベースのフォーマットを生成
  • 46. class PeopleController < ApplicationController before_action :set_message, only: %i(show edit update destroy) include Hypermicrodata::Rails::HtmlBasedJsonRenderer ... end .person{itemscope: true, itemtype: 'http://schema.org/Person', itemid: person_url(@person), data: {main_item: true}} .media .media-image.pull-left = image_tag @person.picture_path, alt: '', itemprop: 'image' .media-body %h1.media-heading %span{itemprop: 'name'}= @person.name = link_to 'collection', people_path, rel: 'collection' Example in HAL (application/hal+json) { "image": "/assets/bob.png", "name": "Bob Smith", "isPartOf": "/people", "_links": { "self": { "href": "http://www.example.com/people/1" }, "type": { "href": "http://schema.org/Person" }, "collection": { "href": "/people" }, "profile": { "href": "/assets/person.alps" } } }
  • 47. Hypermicrodata gemを使った Railsによる設計手順 1. リソース設計 2. 状態遷移図を描く 3. データの名前を対応するURLに結びつける 4. HTMLテンプレート(Haml, Slimなど)を書いて、Microdata でマークアップする (その後、必要ならschema.org定義にないプロファイルと説明を書く)
  • 49. 1. リソース設計 カラム名説明タイプ text noteの内容のテキストtext published_at noteの公開時間datetime (id, created_at, updated_at) (自動生成) $ rails g model Note text:text published_at:datetime model: Note controller: NotesController routing: resources :notes
  • 50. 2. 状態遷移図を描く Railsの Collection & Member リソースパターンから始める (API ver.) item collection Collection Member create*† update*, delete* * 安全でない † 冪等でない
  • 51. Collection of Note Note (text, published_at, created_at, updated_at, id) item collection create*† update*, delete*, publish* next, prev Home notes home * 安全でない † 冪等でない
  • 52. 3. データの名前を対応するURLに 結びつける Collection of Note http://schema.org/ItemList Note http://schema.org/Article text http://schema.org/articleBody published_at http://schema.org/datePublished created_at http://schema.org/dateCreated updated_at http://schema.org/dateModified id (各noteは個別のURLを持つので不要) Home http://schema.org/SiteNavigationElement
  • 53. item IANA ‘item’ & http://schema.org/hasPart collection IANA ‘collection’ & http://schema.org/isPartOf notes - create Activity Streams ‘create' update Activity Streams ‘update’ delete Activity Streams ‘delete’ publish Activity Streams ‘post’ IANA registered Link Relation: http://www.iana.org/assignments/link-relations/ Activity Streams Verbs: http://activitystrea.ms/registry/verbs/
  • 54. 4. HTMLテンプレートとMicrodataを書く Collection of Note %div{itemscope: true, itemtype: 'http://schema.org/ItemList', itemid: notes_url, data: {main_item: true}} - @notes.each do |note| = link_to note.text.truncate(20), note, rel: 'item', itemprop: 'hasPart' /app/views/notes/index.html.haml GET /notes HTTP/1.1 Host: www.example.com Accept: application/vnd.amundsen-uber+json = form_for Note.new do |f| = f.text_field :text = f.submit rel: 'create' { "uber": { "version": "1.0", "data": [{ "url": "http://www.example.com/notes", "name": "ItemList", "data": [ { "name": "hasPart", "rel": "item", "url": "/notes/1" }, { "name": "hasPart", "rel": "item", "url": "/notes/2" }, { "rel": "create", "url": "/notes", "action": "append", "model": "note%5Btext%5D={text}" }, { "rel": "profile", "url": "/assets/note.alps"} ] }] } } Link Form
  • 55. %div{itemscope: true, itemtype: 'http://schema.org/Article', itemid: note_url(@note), data: {main_item: true}} /app/views/notes/show.html.haml %span{itemprop: 'articleBody'}= @note.text %span{itemprop: 'datePublished'}= @note.published_at %span{itemprop: 'dateCreated'}= @note.created_at %span{itemprop: 'dateModified'}= @note.updated_at = form_for @note, method: :put do |f| = f.text_field :text = f.submit rel: 'update' = button_to 'Destroy', @note, method: :delete, rel: 'delete' = button_to 'Publish', publish_note_path(@note), rel: 'publish' unless @note.published? = link_to 'Next note', note_path(@note.next), rel: 'next' if @note.next = link_to 'Prev note', note_path(@note.prev), rel: 'prev' if @note.prev = link_to 'Collection of Note', notes_path, rel: 'collection', itemprop: 'isPartOf' GET /notes/1 HTTP/1.1 Host: www.example.com Accept: application/vnd.amundsen-uber+json Note { "uber": { "version": "1.0", "data": [{ "url": "http://www.example.com/notes/1", "name": "Article", "data": [ { "name": "articleBody", "value": "First note's text" }, { "name": "datePublished", "value": null }, { "name": "dateCreated", "value": "2014-09-11T12:00:31+09:00" }, { "name": "dateModified", "value": "2014-09-11T12:00:31+09:00" }, { "name": "isPartOf", "rel": "collection", "url": "/notes" }, { "rel": "update", "url": "/notes/1", "action": "replace", "model": "note%5Btext%5D={text}" }, { "rel": "delete", "url": "/notes/1", "action": "remove" }, { "rel": "publish", "url": "/notes/1/publish", "action": "append" }, { "rel": "next", "url": "/notes/2" }, { "rel": "profile", "url": "/assets/note.alps" } ] }] } }
  • 56. %div{itemscope: true, itemtype: 'http://schema.org/Article', itemid: note_url(@note), data: {main_item: true}} %span{itemprop: 'articleBody'}= @note.text %span{itemprop: 'datePublished'}= @note.published_at %span{itemprop: 'dateCreated'}= @note.created_at %span{itemprop: 'dateModified'}= @note.updated_at = form_for @note, method: :put do |f| = f.text_field :text = f.submit rel: 'update' = button_to 'Destroy', @note, method: :delete, rel: 'delete' = button_to 'Publish', publish_note_path(@note), rel: 'publish' unless @note.published? = link_to 'Next note', note_path(@note.next), rel: 'next' if @note.next = link_to 'Prev note', note_path(@note.prev), rel: 'prev' if @note.prev = link_to 'Collection of Note', notes_path, rel: 'collection', itemprop: 'isPartOf' Note = button_to 'Publish', publish_note_path(@note), = link_to 'Next note', note_path(@note.next), = link_to 'Prev note', note_path(@note.prev), { "uber": { rel: 'publish' unless @note.published? rel: 'next' if @note.next rel: 'prev' if @note.prev "version": "1.0", "data": [{ "url": "http://www.example.com/notes/1", "name": "Article", "data": [ 条件の表現 publishできるが prevには行けない { "name": "articleBody", "value": "First note's text" }, { "name": "datePublished", "value": null }, { "name": "dateCreated", "value": "2014-09-11T12:00:31+09:00" }, { "{ rel": "name": "publish", "dateModified", "url": "value": "/"2014-notes/09-11T12:1/publish", 00:31+09:00" }, "{ action": "name": "isPartOf", "append" "rel": }, "collection", "url": "/notes" }, { "rel": "update", "url": "/notes/1", "action": "replace", { "rel": "model": "next", "note%5Btext%"url": 5D={text}" "/notes/}, 2" }, { "rel": "delete", "url": "/notes/1", "action": "remove" }, { "rel": "publish", "url": "/notes/1/publish", "action": "append" }, { "rel": "next", "url": "/notes/2" }, { "rel": "profile", "url": "/assets/note.alps" } ] }] } }
  • 58. メリット 1: DRY • リンクとフォームをHTMLテンプレートに一度 書けば、JSON生成時にも再利用できる • Microdataマークアップもそのまま再利用できる • Bonus: HTMLのMicrodataはSEO効果を上げる (JSONにも可能性あり)
  • 59. メリット 2: リンクとフォームを 意識できる • JSON Web APIを作るときには、状態遷移の重要 性を見落としやすい • APIをHTMLのWebアプリのように表現すること で、状態遷移に着目して適切にリンクとフォー ムを実装できる
  • 60. メリット 3: 制約 • 「HTMLドキュメントをMicrodataでマークアップし て、それを一定のルールでフォーマットされた JSONに変換する」という制約 • この制約はよりよい設計のガイド • “Constraints are liberating” 「制約は自由をもたらす」
  • 61. もしJSONだけを書くときは 注意すること • リンク・フォームを意識するために: • 状態遷移図を描きましょう • APIを疎結合に保つために: • model.to_json の代わりに Jbuilder/RABL のようなビューテンプレートや リプレゼンターを使いましょう • リンクとフォームを持ったJSONベースのフォーマットを使いましょう • さらに schema.org のような標準名を使うとベター
  • 62. “WebアプリとWeb APIを分けて考えない” – 「Webを支える技術」@yohei
  • 63. 結論: Web APIはHTML Webアプリと 同じように設計しよう • Web APIは特別なものではなく、ただ表現 フォーマットが違うだけ • 状態遷移図を描いて状態遷移を意識すること で、リンクやフォームを忘れずにすむ
  • 64. 最後に • 残念ながら、JSONフォーマット、クライアント実 装やライブラリにはデファクトスタンダードがない • RESTの制約・原則を意識するともっとうまくでき る • ハイパーメディアはRESTの最も重要な要素の1つで 変化に適応できるWeb APIへの重要なステップ
  • 65. よりよい、変化に適応できるWeb APIを作りましょう Thank you for your attention. References • L. Richardson & M. Amundsen “RESTful Web APIs” (O’Reilly) • 山本陽平 “Webを支える技術” (技術評論社) • Designing for Reuse: Creating APIs for the Future http://www.oscon.com/oscon2014/public/schedule/detail/34922 • API Design Workshop 配布資料 http://events.layer7tech.com/tokyo-wrk • https://speakerdeck.com/zdne/robust-mobile-clients-v2 • http://www.slideshare.net/yohei/webapi-36871915 • http://smizell.com/weblog/2014/solving-fizzbuzz-with-hypermedia • 山口 徹 “Web API デザインの鉄則” WEB+DB PRESS Vol.82