Tel Aviv, 2017Volodymyr Tsukur @ Engineering Meetup
Hypermedia APIs
and <HATEOAS>
REST
Volodymyr Tsukur
partner @
software
engineer @
flushdia vtsukur
program
committee @
Web / HTTP API
Richardson Maturity Model
6
{
"user": "Noah",
"title": "Meets expectations",
"comment": "hey dude,
you make America Great Again!",
"rank": 10
}
Trump Feedback API
7
{
"user": "Shai",
"title": "!",
"comment": "oh you s** ** a bi***,
how could people elect someone like
you, ******* ******* ???",
"rank": 1
}
Trump Feedback API
DEMO TIME !
9
Method URL Task
POST /reviews Create
GET /reviews View all
GET /reviews/{id} Get
PATCH / PUT /reviews/{id} Update
DELETE /reviews/{id} Delete
CRUD Style API
if (status == Status.NEW) {
submittedAt = LocalDateTime.now()
status = Status.SUBMITTED
} …
CRUD is NOT enough
create submit accept
update
delete
NEW
DELETED
SUBMITTED ACCEPTED
12
Method URL Task
PUT /reviews/{id}/submission Submit
PUT /reviews/{id}/acceptance Accept
GET /reviews/search/accepted
Get accepted
reviews
API Changes
DEMO TIME !
/uri Style Adoption?
43%
Richardson Maturity Model
17
Task Method URL
Update PATCH /reviews/{id}
Delete DELETE /reviews/{id}
Submit PUT /reviews/{id}/submission
Accept PUT /reviews/{id}/acceptance
URL Binding & Construction
URL Change Drivers
URL Change Drivers
• monolith → micro-services
• deployment requirements / proxies
• resource renaming
• optimization by client proximity
• caching
• …
20
Task Method URL
Update
(only if NEW) PATCH /reviews/{id}
Delete
(only if NEW) DELETE /reviews/{id}
Submit
(only if NEW) PUT /reviews/{id}/submission
Accept
(only if
SUBMITTED)
PUT /reviews/{id}/acceptance
"Figuring" Out the Flow
Security!
22
Task Method URL
Update
(only if NEW and user
has permissions)
PATCH /reviews/{id}
Delete
(only if NEW and user
has permissions)
DELETE /reviews/{id}
Submit
(only if NEW and user
has permissions)
PUT /reviews/{id}/submission
Accept
(only if SUBMITTED and
user has permissions)
PUT /reviews/{id}/acceptance
Security!
"Hypermedia" =
{
"user": "Aviran",
"title": "...",
…
}
data
{
…
"_links": {
"submission": {
"href": "/reviews/7/submission"
},
"update": {
"href": "/reviews/7"
},
"deletion": {
"href": "/reviews/7"
}
}
}
link
+
26
Link Relation Task Method
update Update PATCH
deletion Delete DELETE
submission Submit PUT
acceptance Accept PUT
Hypermedia API
DEMO TIME !
Hypermedia Client
if (review._links.has("submission")) {
// draw submit button / UI
}
Non-Hypermedia Client
Hypermedia Client
"Simple" Hypermedia
āœ“where to go?
āœ“when?
- how?
"I want hypermedia!" (2014)
0 %
7 %
14 %
21 %
28 %
Hypermedia SOAP CRUD
40%
"I want hypermedia!" (2015)
«A REST API should spend almost all of its
descriptive effort in defining the media type(s)
used for representing resources and driving
application state, or in defining extended relation
names and/or hypertext-enabled mark-up for
existing standard media types.Ā»
Roy T. Fielding, 2008
Hypertext Application Language
Mason{
"name": "Aviran",
"title": "…",
…
"@controls": {
"user": {
"href": "/users/3"
},
"review-submission": {
"href": "/reviews/7/submission",
"method": "PUT"
}
}
}
Hypermedia Factors
level of hypermedia support
CL = Link Semantics
"_links": {
"review": {
"href": "/reviews/7"
}
}
IANA Link Relations
Name Description RFC
self Conveys an identifier for the link's context. RFC4287
first An IRI that refers to the furthest preceding resource in a series of resources. RFC5988
last An IRI that refers to the furthest following resource in a series of resources. RFC5988
up Refers to a parent document in a hierarchy of documents. RFC5988
item
The target IRI points to a resource that is a member of the collection
represented by the context IRI. RFC6573
collection
The target IRI points to a resource which represents the collection resource for
the context IRI. RFC6573
edit Refers to a resource that can be used to edit the link's context. RFC5023
prev/previous
Indicates that the link's context is a part of a series, and that the previous in the
series is the link target. HTML5
next
Indicates that the link's context is a part of a series, and that the next in the
series is the link target. HTML5
IANA Link Relations
Name Description RFC
create-form
The target IRI points to a resource where a submission form can be
obtained. RFC6861
edit-form
The target IRI points to a resource where a submission form for editing
associated resource can be obtained. RFC6861
payment Indicates a resource where payment is accepted RFC5988
latest-version
Points to a resource containing the latest (e.g., current) version of the
context. RFC5829
profile
Identifying that a resource representation conforms to a certain profile,
without affecting the non-profile semantics of the resource representation. RFC6906
search
Refers to a resource that can be used to search through the link's context
and related resources. OpenSearch
index Refers to an index. HTML4
about Refers to a resource that is the subject of the link's context. RFC6903
help Refers to context-sensitive help. HTML5
CL = Link Semantics
<link rel="stylesheet" src="styles.css" />
LE = Link Outbound
"_links": {
"user": {
"href": "/users/7"
}
}
LE = Link Outbound
<a href="/review/1536c64.html">
Shai says "!", rating: 1
</a>
LE = Link Embedded
"_embedded": {
"ratings": [
{ "id": "7", … },
{ "id": "8", … },
]
}
LE = Link Embedded
<img src="/images/cities/tel-aviv.jpg">
LT = Templated Queries
"_links": {
"review-by-id": {
"href": "/reviews{/id}",
"templated": true
}
}
LT = Templated Queries
"_links": {
"reviews": {
"href": "/reviews{?page,size,sort}",
"templated": true
}
}
RFC 6570
LT = Templated Queries
<form method="get" action="/hotels/search">
<input name="query" type="text">
<input type="submit">
</form>
LN = Non-Idemp. Updates
"actions": [
{
"name": "create-review",
"method": "POST",
"href": "/reviews",
"type": "application/json",
"fields": [
{ "name": "user", "type": "text" },
{ "name": "title", "type": "text" },
{ "name": "comment", "type": "text" },
{ "name": "rank", "type": "number" }, …
]
}
]
<form method="post" action="/reviews">
<input name="user" type="text">
<input name="title" type="text">
<input name="comment" type="text">
…
<input type="submit">
</form>
LN = Non-Idemp. Updates
LN = Idempotent Updates
"actions": [
{
"name": "delete-review",
"method": "DELETE",
"href": "/reviews/7"
}
]
CM = Method Modification
"actions": [
{
"name": "delete-rating",
"method": "DELETE",
"href": "/ratings/1"
}
]
CR = Read Modification
"_links": {
"ballot": [
{
"name": "ballot-json",
"href": "/reviews/7",
"type": "application/json"
}
{
"name": "ballot-xml",
"href": "/reviews/7",
"type": "application/xml"
}
]
}
Hypermedia Factors
?What about and
Hypermedia Factors
HTML XML JSON
LE ā©— āŠ— āŠ—
LO ā©— āŠ— āŠ—
LT ā©— āŠ— āŠ—
LN ā©— āŠ— āŠ—
LI āŠ— āŠ— āŠ—
CR āŠ— āŠ— āŠ—
CU ā©— āŠ— āŠ—
CM ā©— āŠ— āŠ—
CL ā©— āŠ— āŠ—
JSON-based Media Types
JSON-LD JSON API HAL Cj Siren Mason Uber
LE ā©— ā©— ā©— ā©— ā©— ā©— ā©—
LO ā©— ā©— ā©— ā©— ā©— ā©— ā©—
LT āŠ— ā©— ā©— ā©— āŠ— ā©— ā©—
LN āŠ— āŠ— āŠ— ā©— ā©— ā©— ā©—
LI āŠ— āŠ— āŠ— ā©— ā©— ā©— ā©—
CR āŠ— āŠ— ā©— āŠ— ā©— ā©— ā©—
CU āŠ— āŠ— āŠ— āŠ— ā©— ā©— ā©—
CM āŠ— āŠ— āŠ— āŠ— ā©— ā©— ā©—
CL ā©— ā©— ā©— ā©— ā©— ā©— ā©—
Before Choosing Media Type
• list information client would want
from the API
• draw state diagram
-think "tasks"
-"(non-)idempotent", "(un-)safe"
{
"@id": "http://trump.feedback/reviews/7",
"@context": "http://trump.feedback/schema/review.jsonld",
"user": "Shai",
"title": "!",
"comment": "oh you s** ** a bi*** ...",
"rank": 1,
…
}
JSON-LD
{
"@context": {
"user": "http://schema.org/name",
"title": "https://schema.org/title",
"comment": "https://schema.org/comment",
"rank": "https://schema.org/ratingValue"
…
}
}
http://trump-feedback/schema/rating.jsonld
{
"@id": "http://trump-feedback/reviews/7",
…
"supportedOperations": [
{
"@type": "ReviewSubmission",
"method": "PUT",
"expects": "#Review"
}
]
}
JSON-LD + Hydra
{
"class": [ "review" ],
"properties": {
"user": "Aviran",
"title": "...",
…
},
"links": …,
"actions": [
{
"name": "review-submission",
"href": "/reviews/7",
"method": "PUT",
…
}
]
}
SIREN
CL = Link Semantics
"_links": {
"review": {
"href": "/reviews/7"
}
}
CL = Link Semantics
"_links": {
"http://trump-feedback/rels/review": {
"href": "/reviews/7"
}
}
CL = Link Semantics
"_links": {
"urn:trump-feedback/rels/review": {
"href": "/reviews/1"
}
}
CL = Link Semantics
"_links": {
"trump-feedback:review": {
"href": "/reviews/1"
}
}
CompactURIE
trump-feedback=
http://trump-feedback/rels/{rel}
trump-feedback:review
http://trump-feedback.com/rels/review
DEMO TIME !
Documentation
• no URLs except of the entry point
• resources
• links (namespaces)
• HTTP status codes, verbs
• authentication, rate limiting
• errors
Mason{
"name": "Aviran",
"title": "...",
…
"@namespaces": {
"trump-feedback": { "name": "http://trump-feedback/rels/" }
},
"@controls": {
"trump-feedback:user": { "href": "/users/3" },
"trump-feedback:review-submission": {
"href": "/reviews/7/submission",
"method": "PUT"
}
}
}
Profiles
āœ“where to go?
āœ“when?
āœ“how?
DEMO TIME !
Richardson Maturity Model
References
1. http://www.google.com.ua/trends/explore#q=web%20api%2C%20rest%20api&cmpt=q&tz=
2. http://finance.i.ua/market/
3. http://projects.spring.io/spring-boot/
4. http://projects.spring.io/spring-data/
5. http://docs.spring.io/spring-data/jpa/docs/1.7.2.RELEASE/reference/html/
6. http://projects.spring.io/spring-data-rest/
7. http://docs.spring.io/spring-data/rest/docs/2.3.0.RELEASE/reference/html/
8. https://spring.io/blog/2014/07/14/spring-data-rest-now-comes-with-alps-metadata
9. http://projects.spring.io/spring-hateoas/
10. http://docs.spring.io/spring-hateoas/docs/0.17.0.RELEASE/reference/html/
11. https://github.com/spring-projects/spring-restdocs
12. https://blog.akana.com/hypermedia-apis
13. http://www.apiacademy.co/lessons/api-design/web-api-architectural-styles
14. http://www.programmableweb.com/news/modern-api-architectural-styles-offer-developers-choices/2014/06/13
15. https://en.wikipedia.org/wiki/Hypermedia
16. http://stateless.co/hal_specification.html
17. https://github.com/kevinswiber/siren
18. https://www.mnot.net/blog/2013/06/23/linking_apis
19. http://oredev.org/2010/sessions/hypermedia-apis
20. http://vimeo.com/75106815
21. https://www.innoq.com/blog/st/2012/06/hypermedia-benefits-for-m2m-communication/
22. http://ws-rest.org/2014/sites/default/files/wsrest2014_submission_12.pdf
23. http://www.infoq.com/news/2014/03/ca-api-survey
24. https://twitter.com/hypermediaapis
25. https://www.youtube.com/watch?v=hdSrT4yjS1g
26. https://www.youtube.com/watch?v=mZ8_QgJ5mbs
27. http://nordsc.com/ext/classification_of_http_based_apis.html
28. http://soabits.blogspot.no/2013/12/selling-benefits-of-hypermedia.html
29. https://github.com/mamund/Building-Hypermedia-APIs
30. http://tech.blog.box.com/2013/04/get-developer-hugs-with-rich-error-handling-in-your-api/

Hypermedia APIs and HATEOAS / Wix Engineering

  • 1.
    Tel Aviv, 2017VolodymyrTsukur @ Engineering Meetup Hypermedia APIs and <HATEOAS>
  • 2.
    REST Volodymyr Tsukur partner @ software engineer@ flushdia vtsukur program committee @
  • 3.
  • 4.
  • 6.
    6 { "user": "Noah", "title": "Meetsexpectations", "comment": "hey dude, you make America Great Again!", "rank": 10 } Trump Feedback API
  • 7.
    7 { "user": "Shai", "title": "!", "comment":"oh you s** ** a bi***, how could people elect someone like you, ******* ******* ???", "rank": 1 } Trump Feedback API
  • 8.
  • 9.
    9 Method URL Task POST/reviews Create GET /reviews View all GET /reviews/{id} Get PATCH / PUT /reviews/{id} Update DELETE /reviews/{id} Delete CRUD Style API
  • 11.
    if (status ==Status.NEW) { submittedAt = LocalDateTime.now() status = Status.SUBMITTED } … CRUD is NOT enough create submit accept update delete NEW DELETED SUBMITTED ACCEPTED
  • 12.
    12 Method URL Task PUT/reviews/{id}/submission Submit PUT /reviews/{id}/acceptance Accept GET /reviews/search/accepted Get accepted reviews API Changes
  • 13.
  • 14.
  • 15.
  • 17.
    17 Task Method URL UpdatePATCH /reviews/{id} Delete DELETE /reviews/{id} Submit PUT /reviews/{id}/submission Accept PUT /reviews/{id}/acceptance URL Binding & Construction
  • 18.
  • 19.
    URL Change Drivers •monolith → micro-services • deployment requirements / proxies • resource renaming • optimization by client proximity • caching • …
  • 20.
    20 Task Method URL Update (onlyif NEW) PATCH /reviews/{id} Delete (only if NEW) DELETE /reviews/{id} Submit (only if NEW) PUT /reviews/{id}/submission Accept (only if SUBMITTED) PUT /reviews/{id}/acceptance "Figuring" Out the Flow
  • 21.
  • 22.
    22 Task Method URL Update (onlyif NEW and user has permissions) PATCH /reviews/{id} Delete (only if NEW and user has permissions) DELETE /reviews/{id} Submit (only if NEW and user has permissions) PUT /reviews/{id}/submission Accept (only if SUBMITTED and user has permissions) PUT /reviews/{id}/acceptance Security!
  • 25.
    "Hypermedia" = { "user": "Aviran", "title":"...", … } data { … "_links": { "submission": { "href": "/reviews/7/submission" }, "update": { "href": "/reviews/7" }, "deletion": { "href": "/reviews/7" } } } link +
  • 26.
    26 Link Relation TaskMethod update Update PATCH deletion Delete DELETE submission Submit PUT acceptance Accept PUT Hypermedia API
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
    "Simple" Hypermedia āœ“where togo? āœ“when? - how?
  • 32.
    "I want hypermedia!"(2014) 0 % 7 % 14 % 21 % 28 % Hypermedia SOAP CRUD
  • 33.
  • 36.
    «A REST APIshould spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state, or in defining extended relation names and/or hypertext-enabled mark-up for existing standard media types.» Roy T. Fielding, 2008
  • 37.
  • 38.
    Mason{ "name": "Aviran", "title": "…", … "@controls":{ "user": { "href": "/users/3" }, "review-submission": { "href": "/reviews/7/submission", "method": "PUT" } } }
  • 39.
    Hypermedia Factors level ofhypermedia support
  • 40.
    CL = LinkSemantics "_links": { "review": { "href": "/reviews/7" } }
  • 41.
    IANA Link Relations NameDescription RFC self Conveys an identifier for the link's context. RFC4287 first An IRI that refers to the furthest preceding resource in a series of resources. RFC5988 last An IRI that refers to the furthest following resource in a series of resources. RFC5988 up Refers to a parent document in a hierarchy of documents. RFC5988 item The target IRI points to a resource that is a member of the collection represented by the context IRI. RFC6573 collection The target IRI points to a resource which represents the collection resource for the context IRI. RFC6573 edit Refers to a resource that can be used to edit the link's context. RFC5023 prev/previous Indicates that the link's context is a part of a series, and that the previous in the series is the link target. HTML5 next Indicates that the link's context is a part of a series, and that the next in the series is the link target. HTML5
  • 42.
    IANA Link Relations NameDescription RFC create-form The target IRI points to a resource where a submission form can be obtained. RFC6861 edit-form The target IRI points to a resource where a submission form for editing associated resource can be obtained. RFC6861 payment Indicates a resource where payment is accepted RFC5988 latest-version Points to a resource containing the latest (e.g., current) version of the context. RFC5829 profile Identifying that a resource representation conforms to a certain profile, without affecting the non-profile semantics of the resource representation. RFC6906 search Refers to a resource that can be used to search through the link's context and related resources. OpenSearch index Refers to an index. HTML4 about Refers to a resource that is the subject of the link's context. RFC6903 help Refers to context-sensitive help. HTML5
  • 43.
    CL = LinkSemantics <link rel="stylesheet" src="styles.css" />
  • 44.
    LE = LinkOutbound "_links": { "user": { "href": "/users/7" } }
  • 45.
    LE = LinkOutbound <a href="/review/1536c64.html"> Shai says "!", rating: 1 </a>
  • 46.
    LE = LinkEmbedded "_embedded": { "ratings": [ { "id": "7", … }, { "id": "8", … }, ] }
  • 47.
    LE = LinkEmbedded <img src="/images/cities/tel-aviv.jpg">
  • 48.
    LT = TemplatedQueries "_links": { "review-by-id": { "href": "/reviews{/id}", "templated": true } }
  • 49.
    LT = TemplatedQueries "_links": { "reviews": { "href": "/reviews{?page,size,sort}", "templated": true } }
  • 50.
  • 51.
    LT = TemplatedQueries <form method="get" action="/hotels/search"> <input name="query" type="text"> <input type="submit"> </form>
  • 52.
    LN = Non-Idemp.Updates "actions": [ { "name": "create-review", "method": "POST", "href": "/reviews", "type": "application/json", "fields": [ { "name": "user", "type": "text" }, { "name": "title", "type": "text" }, { "name": "comment", "type": "text" }, { "name": "rank", "type": "number" }, … ] } ]
  • 53.
    <form method="post" action="/reviews"> <inputname="user" type="text"> <input name="title" type="text"> <input name="comment" type="text"> … <input type="submit"> </form> LN = Non-Idemp. Updates
  • 54.
    LN = IdempotentUpdates "actions": [ { "name": "delete-review", "method": "DELETE", "href": "/reviews/7" } ]
  • 55.
    CM = MethodModification "actions": [ { "name": "delete-rating", "method": "DELETE", "href": "/ratings/1" } ]
  • 56.
    CR = ReadModification "_links": { "ballot": [ { "name": "ballot-json", "href": "/reviews/7", "type": "application/json" } { "name": "ballot-xml", "href": "/reviews/7", "type": "application/xml" } ] }
  • 57.
  • 58.
    Hypermedia Factors HTML XMLJSON LE ā©— āŠ— āŠ— LO ā©— āŠ— āŠ— LT ā©— āŠ— āŠ— LN ā©— āŠ— āŠ— LI āŠ— āŠ— āŠ— CR āŠ— āŠ— āŠ— CU ā©— āŠ— āŠ— CM ā©— āŠ— āŠ— CL ā©— āŠ— āŠ—
  • 59.
    JSON-based Media Types JSON-LDJSON API HAL Cj Siren Mason Uber LE ā©— ā©— ā©— ā©— ā©— ā©— ā©— LO ā©— ā©— ā©— ā©— ā©— ā©— ā©— LT āŠ— ā©— ā©— ā©— āŠ— ā©— ā©— LN āŠ— āŠ— āŠ— ā©— ā©— ā©— ā©— LI āŠ— āŠ— āŠ— ā©— ā©— ā©— ā©— CR āŠ— āŠ— ā©— āŠ— ā©— ā©— ā©— CU āŠ— āŠ— āŠ— āŠ— ā©— ā©— ā©— CM āŠ— āŠ— āŠ— āŠ— ā©— ā©— ā©— CL ā©— ā©— ā©— ā©— ā©— ā©— ā©—
  • 60.
    Before Choosing MediaType • list information client would want from the API • draw state diagram -think "tasks" -"(non-)idempotent", "(un-)safe"
  • 61.
  • 62.
    { "@context": { "user": "http://schema.org/name", "title":"https://schema.org/title", "comment": "https://schema.org/comment", "rank": "https://schema.org/ratingValue" … } } http://trump-feedback/schema/rating.jsonld
  • 63.
  • 64.
    { "class": [ "review"], "properties": { "user": "Aviran", "title": "...", … }, "links": …, "actions": [ { "name": "review-submission", "href": "/reviews/7", "method": "PUT", … } ] } SIREN
  • 65.
    CL = LinkSemantics "_links": { "review": { "href": "/reviews/7" } }
  • 66.
    CL = LinkSemantics "_links": { "http://trump-feedback/rels/review": { "href": "/reviews/7" } }
  • 67.
    CL = LinkSemantics "_links": { "urn:trump-feedback/rels/review": { "href": "/reviews/1" } }
  • 68.
    CL = LinkSemantics "_links": { "trump-feedback:review": { "href": "/reviews/1" } }
  • 69.
  • 70.
  • 71.
    Documentation • no URLsexcept of the entry point • resources • links (namespaces) • HTTP status codes, verbs • authentication, rate limiting • errors
  • 72.
    Mason{ "name": "Aviran", "title": "...", … "@namespaces":{ "trump-feedback": { "name": "http://trump-feedback/rels/" } }, "@controls": { "trump-feedback:user": { "href": "/users/3" }, "trump-feedback:review-submission": { "href": "/reviews/7/submission", "method": "PUT" } } }
  • 73.
  • 74.
  • 75.
  • 77.
    References 1. http://www.google.com.ua/trends/explore#q=web%20api%2C%20rest%20api&cmpt=q&tz= 2. http://finance.i.ua/market/ 3.http://projects.spring.io/spring-boot/ 4. http://projects.spring.io/spring-data/ 5. http://docs.spring.io/spring-data/jpa/docs/1.7.2.RELEASE/reference/html/ 6. http://projects.spring.io/spring-data-rest/ 7. http://docs.spring.io/spring-data/rest/docs/2.3.0.RELEASE/reference/html/ 8. https://spring.io/blog/2014/07/14/spring-data-rest-now-comes-with-alps-metadata 9. http://projects.spring.io/spring-hateoas/ 10. http://docs.spring.io/spring-hateoas/docs/0.17.0.RELEASE/reference/html/ 11. https://github.com/spring-projects/spring-restdocs 12. https://blog.akana.com/hypermedia-apis 13. http://www.apiacademy.co/lessons/api-design/web-api-architectural-styles 14. http://www.programmableweb.com/news/modern-api-architectural-styles-offer-developers-choices/2014/06/13 15. https://en.wikipedia.org/wiki/Hypermedia 16. http://stateless.co/hal_specification.html 17. https://github.com/kevinswiber/siren 18. https://www.mnot.net/blog/2013/06/23/linking_apis 19. http://oredev.org/2010/sessions/hypermedia-apis 20. http://vimeo.com/75106815 21. https://www.innoq.com/blog/st/2012/06/hypermedia-benefits-for-m2m-communication/ 22. http://ws-rest.org/2014/sites/default/files/wsrest2014_submission_12.pdf 23. http://www.infoq.com/news/2014/03/ca-api-survey 24. https://twitter.com/hypermediaapis 25. https://www.youtube.com/watch?v=hdSrT4yjS1g 26. https://www.youtube.com/watch?v=mZ8_QgJ5mbs 27. http://nordsc.com/ext/classification_of_http_based_apis.html 28. http://soabits.blogspot.no/2013/12/selling-benefits-of-hypermedia.html 29. https://github.com/mamund/Building-Hypermedia-APIs 30. http://tech.blog.box.com/2013/04/get-developer-hugs-with-rich-error-handling-in-your-api/