Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Spring HATEOAS
Search
Dai Yamasaki
November 15, 2019
Programming
0
1.1k
Spring HATEOAS
JSUG勉強会 2019その10 SpringOne Platform 2019報告会
Dai Yamasaki
November 15, 2019
Tweet
Share
Other Decks in Programming
See All in Programming
なぜ適用するか、移行して理解するClean Architecture 〜構造を超えて設計を継承する〜 / Why Apply, Migrate and Understand Clean Architecture - Inherit Design Beyond Structure
seike460
PRO
3
780
PicoRuby on Rails
makicamel
2
130
システム成長を止めない!本番無停止テーブル移行の全貌
sakawe_ee
1
210
スタートアップの急成長を支えるプラットフォームエンジニアリングと組織戦略
sutochin26
1
6k
チームのテスト力を総合的に鍛えて品質、スピード、レジリエンスを共立させる/Testing approach that improves quality, speed, and resilience
goyoki
5
920
RailsGirls IZUMO スポンサーLT
16bitidol
0
190
Rails Frontend Evolution: It Was a Setup All Along
skryukov
0
160
Node-RED を(HTTP で)つなげる MCP サーバーを作ってみた
highu
0
120
今ならAmazon ECSのサービス間通信をどう選ぶか / Selection of ECS Interservice Communication 2025
tkikuc
21
4k
Railsアプリケーションと パフォーマンスチューニング ー 秒間5万リクエストの モバイルオーダーシステムを支える事例 ー Rubyセミナー 大阪
falcon8823
5
1.1k
ソフトウェア品質を数字で捉える技術。事業成長を支えるシステム品質の マネジメント
takuya542
2
13k
新メンバーも今日から大活躍!SREが支えるスケールし続ける組織のオンボーディング
honmarkhunt
5
7.6k
Featured
See All Featured
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
16k
Bootstrapping a Software Product
garrettdimon
PRO
307
110k
Docker and Python
trallard
44
3.5k
The Pragmatic Product Professional
lauravandoore
35
6.7k
GitHub's CSS Performance
jonrohan
1031
460k
A better future with KSS
kneath
238
17k
Become a Pro
speakerdeck
PRO
29
5.4k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
34
5.9k
Producing Creativity
orderedlist
PRO
346
40k
Optimizing for Happiness
mojombo
379
70k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
20
1.3k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
6
310
Transcript
4QSJOH)"5&0"4 %BJ:BNBTBLJ 5BHCBOHFST *OD
Who am I •Dai Yamasaki •Born to develop •I k6o
dislike Tokyo
r,BNFIBNFIB*** ΧΠέΞΦϦ l6B.BVLF&BPLBb⒖JOBJLB1POP ʢʮͷੜ໋ʢ㲈ओݖʣਖ਼ٛʹΑͬͯӬଓ͢Δʯʣz
Spring HATEOAS - Hypermedia APIs with Spring https://www.youtube.com/watch?v=o4cc6KzNrpI&list=PLAdzTan_eSPRlQ8t4TU5c-AB4SHV939M6&index=46
Who use HATEOAS
Migration script 0.x $ ./migrate-to-1.0.sh Migrating Spring HATEOAS references to
1.0 for files : *.java Adapting ./src/main/java/… … Done! https://github.com/spring-projects/spring-hateoas/tree/master/etc
Hypermedia -JOL -JOL -JOL -JOL
REST ख़ • Level 0 ҰͭͷURLͱҰͭͷHTTPϝιου • Level 1 ҟͳΔURLͱҰͭͷHTTPϝιου
• Level 2 ҟͳΔURLͱҟͳΔHTTPϝιου • Level 3 APIͷϨεϙϯεʹϋΠύʔϦϯΫใΛ࣋ͭ
Hypermedia + REST { "orderID":…, "productID”:…, "quantity":…, "orderValue":…, "_links":[ {
"rel":"customer", "href":"...", }, { "rel":"self", "href":"...", }] }
Hypermedia As The Engine Of Application State H A T
E O A S HATEOAS
Hypermedia + REST { "orderID":…, "productID”:…, "quantity":…, "orderValue":…, "_links":[ {
“rel":"cancel", "href":"...", }, { "rel":"self", "href":"...", }] }
Why HATEOAS • ϦϯΫ͕Θ͔Ε CRUD ͕Ͱ͖Δ • ϏδωεϩδοΫͷྲྀग़Λආ͚Δ ΫϥΠΞϯτϦϯΫͷ༗ແͰஅ •
ϖʔδϯάͷදݱʹ໎Θͳ͍ { "orderID":…, "productID”:…, "quantity":…, "orderValue":…, "_links":[ { “rel":"cancel", "href":"...", }, { "rel":"self", "href":"...", }] }
Spring HATEOAS
Representation Model
Representation Model
Links & Affordance
ΞϑΥʔμϯεʢaffordanceʣͱɺ ڥ͕ಈʹରͯ͠༩͑Δʮҙຯʯͷ͜ͱͰ͋Δɻ ΞϝϦΧͷ֮৺ཧֶऀδΣʔϜζɾJɾΪϒιϯʹΑΔޠͰ͋Γɺ ੜଶޫֶɺੜଶ৺ཧֶͷجఈత֓೦Ͱ͋Δɻ ʮ༩͑Δɺఏڙ͢Δʯͱ͍͏ҙຯͷӳޠ afford ͔ΒΒΕͨɻ Affordances
Affordance https://www.amazon.co.jp/%E3%82%B5%E3%83%B3%E3%82%A2%E3%83%BC%E3%83%88-%E3%81%8A%E3%82%82%E3%81%97%E3%82%8D%E9%A3%9F%E5%99%A8-4%E6%96%87%E5%AD%97%E3%83%9D%E3%83%AA%E3%82%B7%E3%83%BC- %E3%83%9E%E3%82%B0%E3%82%AB%E3%83%83%E3%83%97-SAN1858/dp/B003NEPOTW
Links & Affordances { "name": "Dai Yamasaki", "role": "Developer", "_links":
{ "self": { "href": “/employees/0" }, "employees": { "href": "/employees" } }, "_templates": { "default": { "method": "put", "properties": [ { "name": "name", "required": true }, { "name": "role" } ] }, "partiallyUpdateEmployee": { "method": "patch", "properties": [ { "name": "name" }, { "name": "role" } …
Links & Affordances @GetMapping("/employees/{id}") public EntityModel<Employee> findOne(@PathVariable Integer id) {
Employee employee = employeeRepository.findOneById(id); // ࣗࣗ "self" ͷϦϯΫΛ࡞ WebMvcEmployeeController controller = methodOn(WebMvcEmployeeController.class); Link findOneLink = linkTo(controller.findOne(id)).withSelfRel(); // Affordance ΛؚΊͨใΛฦ͢ return new EntityModel<>( employee, findOneLink .andAffordance( afford(controller.updateEmployee(null, id))) .andAffordance( afford(controller.partiallyUpdateEmployee(null, id)))); }
4FQBSBUFSFTPVSDF Links & Affordances { "_links": { "my-app:payment": {...}, "curies":
[ { "name": "my-app", "href": "http://hoge.com/docs/{rel}", "templated": true }] } } IUUQNZBQQDPNEPDTQBZNFOU
*OMJOFSFTPVSDF { ... "_templates": { "default": { "method": "put", "properties":
[{ "name": "number", "regex": "[0-9]{16}" }] } } } Links & Affordances
.FEJB5ZQFT
5SBWFSTPO @Test void traverson() { Traverson traverson = new Traverson(baseUri,
MediaTypes.HAL_JSON); ParameterizedTypeReference<EntityModel<Actor>> typeReference = new ParameterizedTypeReference<EntityModel<Actor>>() {}; EntityModel<Actor> result = traverson.follow("movies", "movie", “actor") .toObject(typeReference); assertThat(result.getContent().name) .isEqualTo("Dwayne Douglas Johnson"); }
5SBWFSTPO { "_links": { "movie": { "href": "http://localhost:8080/movies/63e0c973-1606-4fe7-b4e3-0de03d2e0c06" } }
} { "title": "Fast & Furious Presents: Hobbs & Shaw", "_links": { "actor": { "href": "http://localhost:8080/actors/f58ebb17-abd8-48fb-b06c-5a912251631c" } } } { "name": "Dwayne Douglas Johnson" } NPWJFT EntityModel<Actor> result = traverson.follow("movies", "movie", “actor") .toObject(typeReference); NPWJF BDUPS
0UIFS • RepresentationModelAssembler • I18N support • LinkRelationProvider
5IBOLT