Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Hyper, Hyper! Bootiful RESTful Hypermedia APIs with Spring

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
Tweet

More Decks by Kai Toedter

Other Decks in Programming

Transcript

  1. Who am I? ▪ Principal Key Expert at Siemens Smart

    Infrastructure ▪ Web Technology Fan ▪ Open-Source Lover ▪ E-mail: [email protected] ▪ Twitter: twitter.com/kaitoedter ▪ Mastodon: https://mastodon.social/@kaitoedter ▪ Github: github.com/toedter 5/12/2023 2 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License.
  2. Show Hands! 5/12/2023 © Kai Tödter, Licensed under a Creative

    Commons Attribution 4.0 International License. 3
  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 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 4
  4. 5/12/2023 © 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
  5. 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 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 6
  6. HAL Structure 5/12/2023 © 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
  7. 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" }, … ] } } 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 8
  8. Spring ▪ Spring Boot ▪ Spring Data REST ▪ Spring

    HATEOAS 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 10
  9. Domain Model Example public class Director { private Long id;

    private String name; public Director(String name) { this.name = name; } … } 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 11
  10. Spring Data REST: Repository @RepositoryRestResource( collectionResourceRel = "directors", path =

    "directors") interface DirectorRepository extends JpaRepository<Director, Long> { } 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 12
  11. Spring Data REST: Repository (2) @RepositoryRestResource( exported = false )

    interface DirectorRepository extends JpaRepository<Director, Long> { } 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 13
  12. Spring Data REST Response { "id": 2, "name": "Frank Darabont",

    "_links": { "self": { "href": "http://localhost:8080/api/directors/2" } } } 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 14
  13. 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 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 15
  14. 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 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 16
  15. HAL Explorer 5/12/2023 © Kai Tödter, Licensed under a Creative

    Commons Attribution 4.0 International License. 18
  16. 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/ 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 19
  17. 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> 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 21
  18. 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 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 22
  19. 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! 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 23
  20. 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 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 24
  21. 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution

    4.0 International License. 25 Representation Models
  22. Representation Models ▪ REST => Representational State Transfer ▪ Manipulation

    of resources through their representations ▪ Domain Model != Representation Model ▪ Spring HATEOAS provides RepresentationModel abstraction 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 26
  23. 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 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 27
  24. 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()); } 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 28
  25. Response in HAL Media Type { "id": 2, "name": "Frank

    Darabont", "_links": { "self": { "href": "http://localhost:8080/api/directors/2" } } } 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 29
  26. “ 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) 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 31
  27. 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 ▪ … 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 32
  28. 5/12/2023 © 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
  29. HAL-FORMS ▪ Designed to provide forms support for HAL ▪

    Created by Mike Amundsen ▪ _templates for possible actions ▪ Spec: https://rwcbook.github.io/hal-forms/ 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 34
  30. “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.” 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 35 Mike Amundsen Source: https://rwcbook.github.io/hal-forms/
  31. 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
  32. 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
  33. 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); 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 38
  34. JSON:API for Spring HATEOAS ▪ Open Source Project ▪ Apache

    2 License ▪ https://github.com/toedter/spring-hateoas- jsonapi ▪ Reference Documentation ▪ API Documentation 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 41
  35. Project Dependencies Maven: <dependency> <groupId>com.toedter</groupId> <artifactId>spring-hateoas-jsonapi</artifactId> <version>2.0.4</version> </dependency> Gradle: implementation

    'com.toedter:spring-hateoas-jsonapi:2.0.4' 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 43
  36. Domain Model Example public class Director { private Long id;

    private String name; public Director(String name) { this.name = name; } … } 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 44
  37. Response in JSON:API media type { "data": { "id": "2",

    "type": "directors", "attributes": { "name": "Frank Darabont" } }, "links": { "self": "http://localhost:8080/api/directors/2" } } 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 45
  38. 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 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 47
  39. Example with Annotations public class Movie { @Id private String

    myId; @JsonApiType private String myType; @JsonApiMeta private String myMeta; private String title; } 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 48
  40. 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" } } } 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 49
  41. More Features ▪ Meta ▪ Relationships ▪ Inclusion ▪ Sparse

    Fieldsets ▪ Errors ▪ Experimental: Affordances 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 50
  42. 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. 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 52
  43. Links ▪ Spring REST Workshop: https://github.com/toedter/rest-spring-workshop ▪ Spring HATEOAS: https://github.com/spring-projects/spring-hateoas

    ▪ JSON:API for Spring HATEOAS: https://github.com/toedter/spring-hateoas-jsonapi 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 54
  44. License ▪ This work is licensed under a Creative Commons

    Attribution 4.0 International License. ▪ See http://creativecommons.org/licenses/by/4.0/ 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 55