RubyKaigi 2014
http://rubykaigi.org/2014/presentation/S-ToruKawamura
Japanese enlargement version http://www.slideshare.net/tkawa1/rubykaigi2014-hypermedia-the-missing-element-enlarged-ja
1 of 50
Downloaded 38 times
More Related Content
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
2. @tkawa
Toru Kawamura
• Freelance Ruby/Rails programmer
• Technology Assistance Partner at
SonicGarden Inc.
• RESTafarian
inspired by Yohei Yamamoto (@yohei)
• Co-organizer of Sendagaya.rb
• Organizer of the
reading group of
“RESTful Web APIs”
7. • Private
• For internal use
• For SPA or dedicated
clients only
• Almost expected,
almost controllable
• Public
• For external use
• For general-purpose
clients
• Less expected,
less controllable
8. “Whether an API should be RESTful or not
depends on the requirement”
– 「WebAPIのこれまでとこれから」by @yohei
http://www.slideshare.net/yohei/webapi-36871915
11. Change is inevitable
!
Web APIs must adapt to changes
変化は避けられない
Web APIは変化に適応しなければならない
12. Two types of Change
With versioning Without versioning
Incompatible Compatible
Breaks clients Does not break clients
Breaking Change Non-Breaking Change
13. Breaking Changes are Harmful
壊す変更は有害
• Terrible user experience
ひどいユーザ体験
• Forces client developers to rewrite/redeploy code
クライアント開発者にコードの書き直し・再デプロイを強いる
• What if on …
14. Because of what?
なぜ起こるの?
With versioning Without versioning
Incompatible Compatible
Breaks clients Does not break clients
Breaking Change Non-Breaking Change
15. Many clients are built from
human-readable documentation
人間が読める説明書から作られる
クライアントがたくさんある
GET /v1/statuses?id=#{id} GET /v1/statuses?id=#{id}
17. Some clients are built from
machine-readable documentation
{
"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": [
機械が読める説明書から作られる
クライアントもある
18. GET /v2/statuses/#{id} GET /v1/statuses?id=#{id} ×Need to regenerate code
{
"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": [
19. {
uber: {
Because of Coupling
version: "1.0",
data: [{
url: "http://www.ishuran.dev/notes/1",
name: "Article",
data: [
• API {
name: changes "articleBody",
should be reflected in clients
value: "First note's text"
},
{
It is name: • value: },
good "datePublished",
null
to split up explanations of the API and
{
embed name: "dateCreated",
value: "2014-them 09-11T12:into 00:31+09:00"
each API response
},
{
name: "dateModified",
value: "2014-09-11T12:00:31+09:00"
• A },
{
lot of assumptions about the API make a tight
name: "isPartOf",
rel: "collection",
coupling
url: "/notes"
密結合のせい
APIの変更がクライアントに反映されるべき
APIの説明を分割して各レスポンスに埋め込むのが良い
APIについての多大な仮定は密結合を生む
20. With versioning Without versioning
Incompatible Compatible
Breaks clients Does not break clients
Breaking Change Non-Breaking Change
because of the Coupling because of the Decoupling
21. Decoupling in a example:
FizzBuzzaaS
• by Stephen Mizell
例で見る疎結合
http://fizzbuzzaas.herokuapp.com/
http://smizell.com/weblog/2014/solving-fizzbuzz-with-hypermedia
• Server knows how to calculate
FizzBuzz for given number (<= 100)
サーバは100までの数のFizzBuzzを計算できる
• Server knows what the next FizzBuzz
will be
サーバは次のFizzBuzzが何になるか知っている
• Client wants all FizzBuzz from one to
the last in order
クライアントは1から最後まで順番にすべてのFizzBuzzが欲しい
http://sef.kloninger.com/posts/
201205fizzbuzz-for-managers.
html
22. Coupled client
密結合なクライアント
answer = HTTP.get("/v1/fizzbuzz?number=#{i}")
puts answer
end
"/v2/fizzbuzz/#{i}"
(1..1000)
(1..100).each do |i|
• Every URL and parameter is hardcoded
• Duplicates the server logic such as counting
up
すべてのURLとパラメータがハードコードされている
カウントアップのようなサーバロジックと同じことをやっている
23. Decoupled client
疎結合なクライアント
root = HTTP.get_root
answer = root.link('first').follow
puts answer
while answer.link('next').present?
answer = answer.link('next').follow
puts answer
end Link ‘next’ is the key
• No hardcoded URLs
• Client doesn’t break when changing
URLs / the restriction
ハードコードされたURLなし
URLや条件を変えてもクライアントは壊れない
24. The “API Call” metaphor is
dangerous
「APIコール」のメタファーは危険
• We need to move away from the paradigm where
a client arranges a URL and parameters in advance
and calls API (like RPC…)
URLとパラメータを用意してAPIを呼ぶというRPCのようなパラダイムから離れよう
• What a client does next should be to choose
from links in the response
== HYPERMEDIA
クライアントが次にすることはリンクから選ぶこと
これがハイパーメディア
25. This is not imaginary
but already present in HTML
これは想像上のものではなく、すでにHTMLにある
26. The HTML Web
• Web apps and websites
have been changing
constantly without
breaking browsers
• Why don’t browsers
break on the HTML Web?
There are links
in HTML
WebアプリやWebサイトはずっと変わり続けているけど
ブラウザは壊れていないのはなぜ?
http://www.youtypeitwepostit.com/messages
27. Workflow in HTML
• Web app includes a
(suggested) workflow
• Workflow is represented
by a sequence of screen
transitions
— Links and Forms
Webアプリはワークフローを含む
ワークフローは一連の画面遷移で表現される
それはリンクとフォーム
”RESTful Web APIs” p.11 Figure 1-7
28. Hypermedia show the workflow
ハイパーメディアはワークフローを示す
• Each screen includes what a
browser can do next
through links and forms like a
“menu”
• A browser chooses from the
“menu” to go to the next
step
• This is HYPERMEDIA and
exactly what FizzBuzzaaS
does
3
4
各画面は次に何ができるかのリンクやフォームの
「メニュー」を含み、ブラウザはその中から選ぶ
これがハイパーメディア
29. One more hint in a Crawler
クローラーにはもう1つヒントが
• Crawlers follow links and can submit some forms
• Crawlers understand the data in an HTML document
and their “meaning”
• How can they do that?
クローラはHTMLの中のデータと意味を理解している
https://support.google.com/webmasters/answer/99170 どうやって?
30. 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>
• Mechanism that embeds structured data within an HTML
document
• Document structure can change without changing data
• Connects data with a URL that roughly represents
the “meaning of data” (this is also a kind of link)
Microdataは構造化データをHTMLに埋め込むしくみ
URLに結びつけることで大まかな「データの意味」も表す
31. 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="is the http://standard www.example.vocabulary com" itemprop="promoted url">www.example.I live in Albuquerque, NM and
by
com</a>
work as an Bing, <span itemprop="Google, title">at <span itemprop="affiliation">Yahoo! engineer</span>
ACME Corp</and Yandex
span>.
</div>
• Mechanism that embeds structured data within an HTML
document
• Document structure can change without changing data
• Connects data with a URL that roughly represents
the “meaning of data” (this is also a kind of link)
http://getschema.org/index.php/Main_Page
32. You could build a Web API in HTML
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” allows clients to extract data from HTML
http://www.w3.org/TR/microdata/#using-the-microdata-dom-api
Microdata DOM APIでHTMLからデータを抽出できる
• Available in JavaScript: https://github.com/termi/Microdata-JS
• There are also some specs for translating Microdata into JSON
MicrodataからJSONに変換もできる
• HTML’s great advantage is that it has links and forms built-in
HTMLはリンクとフォームを持っているのが大きなアドバンテージ
33. But you probably want a
JSON Web API…
でもたぶんJSON Web APIが欲しいよね
data link form
HTML
+Microdata ✓✓ ✓ ✓
JSON ✓ - -
✓✓: including “meaning of data”
• You have to fill in links and forms
(also the meanings of data, if possible)
リンクとフォームを埋めればいい(できればデータの意味も)
34. Links and Forms in JSON
• Use a JSON-based
format that can represent
links and forms
• There are other formats
Siren, Collection+JSON,
Mason, Verbose, etc
data link form
JSON ✓ - -
JSON
+Link header ✓ ✓ -
HAL ✓ ✓ -
JSON-LD ✓✓ ✓ -
JSON-LD
+Hydra ✓✓ ✓ ✓
UBER ✓ ✓ ✓
リンクとフォームを表現できる
JSONベースのフォーマットがある
✓✓: including “meaning of data”
36. Hypermicrodata gem
https://github.com/tkawa/hypermicrodata
• Translate HTML into JSON on Server-side
• Extract not only Microdata but also links and
forms from HTML
• Generate a JSON-based format that naturally fits
with an explanation of meaning of data
サーバサイドでHTMLをJSONに変換
Microdataだけではなく
リンクとフォームもHTMLから抽出
データの意味も表しやすい形で
JSONベースのフォーマットを生成
37. Design procedure in Rails with
Hypermicrodata gem
Hypermicrodata gemを使ったRailsによる設計手順
1. Design resources
2. Draw a state diagram
3. Connect names of data with corresponding URLs
4. Write HTML templates (Haml, Slim, etc) with
Microdata markup
1. リソース設計
2. 状態遷移図を描く
3. データの名前を対応するURLに結びつける
4. HTMLテンプレートを書き
Microdataでマークアップ
(Then, write profiles and explanations that are not defined in
schema.org, if necessary)
38. 1. Design resources
column name short description type
text content text of note text
published_at published time of note datetime
(id, created_at, updated_at) (auto-generated)
$ rails g model Note text:text published_at:datetime
model: Note
controller: NotesController
routing: resources :notes
39. 2. Draw a state diagram
Begin with Collection & Member Resource pattern of Rails (API ver.)
item
collection
Collection Member
create*†
update*, delete*
* unsafe
† non-idempotent
40. Collection
of Note
Note
(text, published_at,
created_at,
updated_at, id)
item
collection
create*†
update*, delete*,
* unsafe
† non-idempotent
publish*
next, prev
Home
notes home
41. 3. Connect names of data with
corresponding URLs
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 (No need because each note has its own URL)
Home http://schema.org/SiteNavigationElement
45. 3 Pros of this design procedure
• DRY
• When providing both HTML and JSON
• Awareness of links and forms
• Framing the API as an HTML Web app gets you
focused on these state transition
• Constraints
• “Constraints are liberating”
この設計手順の3つのメリット
HTMLとJSON両方提供するならDRY
APIをWebアプリと同じように考えることで状態遷移に着目し
リンクとフォームを意識できる
「制約は自由をもたらす」
46. If you want to write only JSON,
you should keep in mind
もしJSONだけを書くときは注意すること
• To stay focused on the link/form pattern:
• Draw a state diagram
リンク・フォームを意識するために
状態遷移図を描きましょう
• To keep your API decoupled:
• Use view templates or representers such as Jbuilder/RABL
instead of model.to_json
疎結合のために、model.to_jsonはやめて
ビューテンプレートを使いましょう
• Use a JSON-based format with links and forms
リンクとフォームを持ったJSONベースのフォーマットを使いましょう
• In addition, it is better to use standard names such as schema.org
schema.orgのような標準名を使うとさらに良いです
48. Conclusion:
Design Your Web API the same way
as an HTML Web App
結論: Web APIはHTML Webアプリと同じように設計しよう
• A Web API is nothing special, It just has a different
representation format
Web APIは特別なものではなく、ただ表現フォーマットが違うだけ
• Awareness of state transitions by drawing a
diagram will remind you of links and forms
状態遷移図を描いて状態遷移を意識することで、リンクやフォームを忘れずにすむ
49. Finally
• Unfortunately, no de-facto standard JSON format,
client implementations, libraries, etc
残念ながら、デファクトスタンダードがない
• We can do better by focusing on the principles and
constraints of REST
RESTの制約・原則を意識するともっとうまくできる
• Hypermedia is one of the most important elements of
REST, and a key step toward building Web APIs
adaptable to change
ハイパーメディアはRESTの最も重要な要素で
変化に適応できるWeb APIへの重要なステップ
50. Build a Better & Adaptable 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