Share
Embed
Hyper, Hyper! Bootiful RESTful Hypermedia APIs with Spring
In this deck, Kai shows how easy it is to develop RESTful Hypermedia APIs with Spring. Kai will specifically address the Spring projects "Spring Data REST" and "Spring HATEOAS". After an introduction to HAL (Hypertext Markup Language), he will show how to implement a Collection REST Resource that uses HAL for pagination. After that we continue with Spring HATEOAS. Kai explains the most important basics and then uses the example of HAL-FORMS to show how the power of hypermedia semantics can be greatly expanded with so-called affordances. Finally, Kai introduces an extension for Spring HATEOAS that he develops himself: JSON:API.
Kai Toedter
May 09, 2023
Transcript
55 slides
-
Who am I? ▪ Distinguished Key Expert at Siemens Smart
Infrastructure ▪ Open-Source Lover ▪ VR Enthusiast and Gamer ▪ E-mail: [email protected] ▪ Mastodon: https://mastodon.social/@kaitoedter ▪ GitHub: github.com/toedter 9/30/2025 2 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. -
Show Hands! 9/30/2025 © Kai Tödter, Licensed under a Creative
Commons Attribution 4.0 International License. 3 -
HATEOAS ▪ Is for “Hypermedia As The Engine Of Application
State” ▪ Very hard to pronounce ☺ ▪ Key concept of REST ▪ WIKIPEDIA: With HATEOAS, a client interacts with a network application whose application servers provide information dynamically through hypermedia 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 4 -
9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution
4.0 International License. 5 HAL Image Source: http://wallpoper.com/images/00/26/43/92/hal-9000_00264392.jpg -
HAL ▪ Is for Hypertext Application Language ▪ Created by
Mike Kelly ▪ Representations for both JSON and XML ▪ Very popular & very simple ▪ Spec: https://tools.ietf.org/html/draft-kelly- json-hal-08 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 6 -
HAL Structure 9/30/2025 © Kai Tödter, Licensed under a Creative
Commons Attribution 4.0 International License. 7 Plain old JSON Properties Links Plain old JSON Properties Links Plain old JSON Properties Links … Embedded Resources Embedded Resources Embedded Resources -
HAL Example { "name": "Ridley Scott", "_links": { "self": {
"href": "https://movies-demo.org/api/directors/89", }, "movies": [ { "href": "https://movies-demo.org/api/movies/93", "title": "Alien" }, … ] } } 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 8 -
9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution
4.0 International License. 9 HAL with Spring -
Spring ▪ Spring Boot ▪ Spring Data REST ▪ Spring
HATEOAS 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 10 -
Domain Model Example public class Director { private Long id;
private String name; public Director(String name) { this.name = name; } … } 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 11 -
Spring Data REST: Repository @RepositoryRestResource( collectionResourceRel = "directors", path =
"directors") interface DirectorRepository extends JpaRepository<Director, Long> { } 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 12 -
Spring Data REST: Repository (2) @RepositoryRestResource( exported = false) interface
DirectorRepository extends JpaRepository<Director, Long> { } 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 13 -
Spring Data REST Response { "id": 2, "name": "Frank Darabont",
"_links": { "self": { "href": "http://localhost:8080/api/directors/2" } } } 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 14 -
Robust Clients ▪ Start from main API ▪ Find link
relations through defined contracts ▪ Follow Links ▪ For navigation ▪ For possible “actions” => Clients are robust regarding changes in link URIs 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 15 -
HAL Explorer ▪ https://github.com/toedter/hal-explorer ▪ Easy integration through WebJar ▪
Supports custom request headers ▪ Supports theming and responsive design ▪ Supported by Spring Data REST 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 16 -
9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution
4.0 International License. 17 Demo -
HAL Explorer 9/30/2025 © Kai Tödter, Licensed under a Creative
Commons Attribution 4.0 International License. 18 -
Spring HATEOAS ▪ Spring basic framework for REST with Hypermedia
support ▪ Supports generic Hypermedia API ▪ Build-in Support for Representations like HAL, HAL-FORMS, UBER, Collection+JSON, … ▪ Community-based media types: JSON:API, Siren ▪ https://docs.spring.io/spring-hateoas/docs/current- SNAPSHOT/reference/html/ 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 19 -
9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution
4.0 International License. 20 Links -
Links ▪ Essential for hypermedia ▪ In REST: How to
navigate to a REST resource ▪ Link semantic/name is called link relation ▪ The relation between a REST resource and the target REST resource ▪ Links are well known from HTML, like <a href="url">link text</a> 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 21 -
Links in Spring HATEOAS Link link = new Link("/my-url"); ▪
A link automatically has a self relation Link link = new Link("/my-url", "my-rel"); ▪ A link with my-rel relation 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 22 -
Link Relations ▪ Many Link relations are standardized by IANA
▪ IANA = Internet Assigned Numbers Authority ▪ https://www.iana.org/assignments/link- relations/link-relations.xhtml ▪ Examples: self, item, next, last, … ▪ Recommendation: Before creating a custom name for a link relation, look up the IANA list! 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 23 -
Links are great! ▪ For providing navigation to useful other
REST resources ▪ For providing domain knowledge to the REST clients, so that they don’t have to compute domain state on there own 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 24 -
9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution
4.0 International License. 25 Representation Models -
Representation Models ▪ REST => Representational State Transfer ▪ Manipulation
of resources through their representations ▪ Domain Model != Representation Model ▪ Spring HATEOAS provides RepresentationModel abstraction 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 26 -
Spring HATEOAS RepresentationModel ▪ RepresentationModel ▪ Root class, for REST
item resources ▪ CollectionModel ▪ For REST collection resources ▪ EntityModel ▪ Convenient wrapper for converting a domain model into a representation model ▪ PagedModel ▪ Addition to CollectionModel for paged collections 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 27 -
Controller Example @GetMapping("/directors/{id}") public ResponseEntity<EntityModel<Director>> findOne(@PathVariable Long id) { return
repository.findById(id) .map(director -> EntityModel.of(director) .add(linkTo(methodOn(DirectorController.class) .findOne(director.getId())).withSelfRel())) .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 28 -
Response in HAL Media Type { "id": 2, "name": "Frank
Darabont", "_links": { "self": { "href": "http://localhost:8080/api/directors/2" } } } 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 29 -
9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution
4.0 International License. 30 Affordances -
“ The affordances of the environment are what it offers
… what it provides or furnishes, either for good or ill. The verb 'to afford' is found in the dictionary, but the noun 'affordance' is not. I have made it up.” James J. Gibson The Ecological Approach to Visual Perception (1986) 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 31 -
Affordances ▪ With Affordances, possible actions on a REST resource
(or Link relation) can be described in more detail, e.g. ▪ What can you do with a REST resource? ▪ Create, Update, Delete, … ▪ Which parameters are mandatory or optional ▪ How would (internationalized) labels be displayed in a user interface ▪ … 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 32 -
9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution
4.0 International License. 33 HAL-FORMS Image Source: http://wallpoper.com/images/00/26/43/92/hal-9000_00264392.jpg Shutdown! Restart -
HAL-FORMS ▪ Designed to provide forms support for HAL ▪
Created by Mike Amundsen ▪ _templates for possible actions ▪ Spec: https://rwcbook.github.io/hal-forms/ 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 34 -
“The HAL-FORMS media type design follows many of the HAL
media type conventions. For this reason, HAL-FORMS "looks like HAL." However, it is important to keep in mind that HAL-FORMS is not the same as HAL — the two should not be thought of as interchangeable in any way.” 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 35 Mike Amundsen Source: https://rwcbook.github.io/hal-forms/ -
Rendering with HAL-FORMS (1) "_templates": { "default": { "title": "Change
Movie", "method": "PUT", "contentType": "", "properties": [ { "name": "imdbId", "prompt": "IMDB Id", "required": true }, … © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 36 -
Rendering with HAL-FORMS (2) "_templates": { "default": { … },
"deleteMovie": { "title": "Delete Movie", "method": "DELETE", "contentType": "", "properties": [] } } © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 37 -
Affordances with Spring HATEOAS public RepresentationModel<?> toModel(Movie movie) { Link
selfLink = linkTo(methodOn(MovieController.class) .findOne(movie.getId())).withSelfRel(); final Affordance updatePartiallyAffordance = afford(methodOn(MovieController.class) .updateMoviePartially(EntityModel.of(movie), movie.getId())); final Affordance deleteAffordance = afford(methodOn(MovieController.class) .deleteMovie(movie.getId())); Link link = selfLink.andAffordance(updatePartiallyAffordance) .andAffordance(deleteAffordance); 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 38 -
9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution
4.0 International License. 39 Demo -
JSON:API for Spring HATEOAS ▪ Open Source Project ▪ Apache
2 License ▪ https://github.com/toedter/spring-hateoas- jsonapi ▪ Reference Documentation ▪ API Documentation 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 41 -
9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution
4.0 International License. 42 -
Project Dependencies Maven: <dependency> <groupId>com.toedter</groupId> <artifactId>spring-hateoas-jsonapi</artifactId> <version>2.1.4</version> </dependency> Gradle: implementation
'com.toedter:spring-hateoas-jsonapi:2.1.4' 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 43 -
Domain Model Example public class Director { private Long id;
private String name; public Director(String name) { this.name = name; } … } 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 44 -
Response in JSON:API media type { "data": { "id": "2",
"type": "directors", "attributes": { "name": "Frank Darabont" } }, "links": { "self": "http://localhost:8080/api/directors/2" } } 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 45 -
9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution
4.0 International License. 46 Annotations -
Annotations ▪ @JsonApiId to mark a JSON:API id ▪ @JsonApiType
to mark a JSON:API type ▪ @JsonApiTypeForClass to mark a class to provide a JSON:API type ▪ @JsonApiRelationships to mark a JSON:API relationship, only used for deserialization ▪ @JsonApiMeta to serialize/deserialize properties to JSON:API meta 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 47 -
Example with Annotations public class Movie { @Id private String
myId; @JsonApiType private String myType; @JsonApiMeta private String myMeta; private String title; } 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 48 -
Annotations Example (2) EntityModel.of(new Movie("1", "MOVIE", "metaValue", "Star Wars")); will
be rendered as { "data": { "id": "1", "type": "MOVIE", "attributes": { "title": "Star Wars" }, "meta": { "myMeta": "metaValue" } } } 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 49 -
More Features ▪ Meta ▪ Relationships ▪ Inclusion ▪ Sparse
Fieldsets ▪ Errors ▪ Experimental: Affordances 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 50 -
9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution
4.0 International License. 51 Demo -
Conclusion With JSON:API for Spring HATEOAS, it is very easy
to support JSON:API (serialization + deserialization) out of the box. With the builder, special JSON:API features like relationships and sparse fieldsets are supported as well. 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 52 -
9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution
4.0 International License. 53 Discussion -
Links ▪ Spring REST Workshop: https://github.com/toedter/spring-rest-workshop ▪ Spring HATEOAS: https://github.com/spring-projects/spring-hateoas
▪ JSON:API for Spring HATEOAS: https://github.com/toedter/spring-hateoas-jsonapi 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 54 -
License ▪ This work is licensed under a Creative Commons
Attribution 4.0 International License. ▪ See http://creativecommons.org/licenses/by/4.0/ 9/30/2025 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 55