Slide 1

Slide 1 text

Bootiful RESTful Hypermedia APIs with Spring Kai Tödter

Slide 2

Slide 2 text

Who am I? ▪ Principal Key Expert at Siemens Smart Infrastructure ▪ Web Technology Fan ▪ Open-Source Lover ▪ E-mail: kai@toedter.com ▪ 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.

Slide 3

Slide 3 text

Show Hands! 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 3

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 9 HAL with Spring

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

Spring Data REST: Repository @RepositoryRestResource( collectionResourceRel = "directors", path = "directors") interface DirectorRepository extends JpaRepository { } 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 12

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 17 Demo

Slide 18

Slide 18 text

HAL Explorer 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 18

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 20 Links

Slide 21

Slide 21 text

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 link text 5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 21

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 25 Representation Models

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

Controller Example @GetMapping("/directors/{id}") public ResponseEntity> 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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 30 Affordances

Slide 31

Slide 31 text

“ 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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

“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/

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 39 Demo

Slide 40

Slide 40 text

{json:api} for Spring HATEOAS

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 42

Slide 43

Slide 43 text

Project Dependencies Maven: com.toedter spring-hateoas-jsonapi 2.0.4 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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 46 Annotations

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 51 Demo

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

5/12/2023 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 53 Discussion

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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