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

Bootiful REST Services with Spring

Bootiful REST Services with Spring

This is the slide deck for my workshop "Bootiful REST Services with Spring". The code with all the exercises is available at https://github.com/toedter/rest-spring-workshop

Kai Toedter

January 08, 2023
Tweet

More Decks by Kai Toedter

Other Decks in Programming

Transcript

  1. Bootiful REST Services with Spring Kai Tödter 4/25/2024 1 ©

    Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License.
  2. Who am I? ▪ Principal Key Expert at Siemens Smart

    Infrastructure ▪ Open-Source Lover ▪ VR Enthusiast and Gamer ▪ E-mail: [email protected] ▪ X (Twitter): twitter.com/kaitoedter ▪ Mastodon: https://mastodon.social/@kaitoedter ▪ Github: github.com/toedter 4/25/2024 2 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License.
  3. Show Hands! 4/25/2024 © Kai Tödter, Licensed under a Creative

    Commons Attribution 4.0 International License. 3
  4. Spring Boot? REST? HATEOAS? HAL/HAL-FORMS? JSON:API? Security? 4/25/2024 © Kai

    Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 4
  5. After this workshop I’ll have an idea how to put

    it all together! 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 5
  6. Outline ▪ Spring Boot ▪ REST & Hypermedia ▪ Spring

    Data REST ▪ Spring HATEOAS ▪ JSON:API ▪ Security 4/25/2024 6 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License.
  7. Slides ▪ You find this slide deck at https://speakerdeck.com/toedter/bootiful- rest-services-with-spring

    ▪ Or just search for “speakerdeck toedter” 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 7
  8. Requirements: Labs on local machine ▪ Your favorite text editor

    or IDE ▪ IntelliJ IDEA, Eclipse, Sublime, … ▪ Java >= 17 (JDK) installed 4/25/2024 8 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License.
  9. Lab 0: Check Build Environment ▪ Install the tutorial sources

    ▪ Clone https://github.com/toedter/spring-rest-workshop ▪ Open terminal and cd into spring-rest-workshop ▪ gradlew build ▪ Linux & Mac: ./gradlew build ▪ If the build is successful, you are ready to go! 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 9
  10. Why Spring Boot? ▪ Fast way to build web applications

    ▪ Inspects your classpath and beans you have configured ▪ You can focus more on business features and less on infrastructure ▪ Easily deployable as microservice 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 11
  11. What does Spring Boot NOT? ▪ Generate code ▪ Change

    your configuration 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 12
  12. HelloController @RestController public class HelloController { @RequestMapping("/") public String index()

    { return "Greetings from Spring Boot!"; } } 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 13
  13. Application @SpringBootApplication public class Application { public static void main(String[]

    args) { SpringApplication .run(Application.class, args); } } 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 14
  14. Controller Test with MockMVC @WebMvcTest(HelloController.class) public class HelloControllerTest { @Autowired

    private MockMvc mockMVC; @Test public void shouldGetGreeting() throws Exception { mockMVC.perform(MockMvcRequestBuilders.get("/") .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().string(equalTo( HelloController.LAB1_GREETINGS_FROM_SPRING_BOOT))); } } 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 15
  15. Integration Test with Random Port @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class

    HelloControllerIntegrationTest { @Autowired private TestRestTemplate restTemplate; @Test public void shouldGetGreeting() throws Exception { ResponseEntity<String> response = restTemplate.getForEntity("/", String.class); assertThat(response.getBody(), equalTo(HelloController.LAB1_GREETINGS_FROM_SPRING_BOOT)); } } 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 16
  16. Lab 1: Task 1 ▪ Open lab1/complete in your IDE

    ▪ Run Application.java ▪ Open browser with localhost:8080 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 17
  17. Lab 1: Task 2 ▪ Open lab1/initial in your IDE

    ▪ Create a Spring Boot based web app ▪ Run it and open your browser with localhost:8080 ▪ Optional: Write some tests! ▪ Get some ideas from …/complete 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 18
  18. 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution

    4.0 International License. 19 REST + Hypermedia Basics
  19. Outline ▪ REST Basics ▪ HATEOAS ▪ Hypermedia with HAL

    ▪ Spring Data REST 4/25/2024 20 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License.
  20. What is REST? ▪ Stands for Representational State Transfer ▪

    Is a Software Architecture Style ▪ was introduced and defined in 2000 by Roy T. Fielding in his doctoral dissertation ▪ REST != CRUD via HTTP 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 21
  21. REST Architectural Constraints ▪ Client-Server ▪ Stateless ▪ Cacheable ▪

    Layered system ▪ Code on demand (optional) ▪ Uniform interface (see next slide) 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 22
  22. Uniform Interface ▪ Identification of resources ▪ Manipulation of resources

    through their representations ▪ Create => HTTP POST ▪ Read => HTTP GET ▪ Update => HTTP PUT, HTTP PATCH ▪ Delete => HTTP DELETE ▪ Self-descriptive messages ▪ Hypermedia as the engine of application state (HATEOAS) 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 23
  23. Richardson Maturity Model Level 3: Hypermedia Controls Level 2: HTTP

    Verbs Level 1: Resources Level 0: The Swamp of POX 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 24 Source: https://martinfowler.com/articles/richardsonMaturityModel.html
  24. HATEOAS ▪ Is for “Hypermedia As The Engine Of Application

    State” ▪ Very hard to pronounce ☺ ▪ Key concept of REST 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 25
  25. “With HATEOAS, a client interacts with a network application whose

    application servers provide information dynamically through hypermedia. A REST client needs little to no prior knowledge about how to interact with an application or server beyond a generic understanding of hypermedia.” 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 26 Wikipedia Source: https://en.wikipedia.org/wiki/HATEOAS
  26. api.github.com 4/25/2024 © Kai Tödter, Licensed under a Creative Commons

    Attribution 4.0 International License. 28 { "current_user_url": "https://api.github.com/user", "current_user_authorizations_html_url": "https://github.com/settings/connections/applications{/client_id}", "authorizations_url": "https://api.github.com/authorizations", "code_search_url": "https://api.github.com/search/code?q={query}{&page,per_page,sort,order}", "commit_search_url": "https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}", "emails_url": "https://api.github.com/user/emails", "emojis_url": "https://api.github.com/emojis", "events_url": "https://api.github.com/events", "feeds_url": "https://api.github.com/feeds", "followers_url": "https://api.github.com/user/followers", "following_url": "https://api.github.com/user/following{/target}", "gists_url": "https://api.github.com/gists{/gist_id}", "hub_url": "https://api.github.com/hub", "issue_search_url": "https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}", "issues_url": "https://api.github.com/issues" }
  27. Hypermedia APIs for Services are like Web Pages with Links

    for Humans 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 29
  28. 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution

    4.0 International License. 30 HAL Image Source: http://wallpoper.com/images/00/26/43/92/hal-9000_00264392.jpg
  29. HAL ▪ Is for Hypertext Application Language ▪ Was created

    by Mike Kelly ▪ Representations for both JSON and XML ▪ Very popular 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 31
  30. HAL Structure 4/25/2024 © Kai Tödter, Licensed under a Creative

    Commons Attribution 4.0 International License. 32 Plain old JSON Properties Links Plain old JSON Properties Links Plain old JSON Properties Links … Embedded Resources Embedded Resources Embedded Resources
  31. HAL Example { "id":1, "text":"hello all!", "_links": { "self": {

    "href":"http://localhost:8080/chatty/api/messages/1" } }, "_embedded": { "author": { "id":"toedter_k" } } } 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 33
  32. Spring ▪ Spring Boot ▪ Spring Data REST ▪ Spring

    HATEOAS 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 34
  33. Spring Data Rest: Domain @Data @Entity @NoArgsConstructor public class Movie

    { @Id private Long id; private String title; private String year; } 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 35
  34. Spring Data REST: Repository @RepositoryRestResource( collectionResourceRel = "movies", path =

    "movies") interface MovieRepository extends CrudRepository<Movie, Long>, PagingAndSortingRepository< Movie, Long> { } 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 36
  35. Spring Data REST: Repository (2) @RepositoryRestResource( exported = false )

    interface MovieRepository extends CrudRepository<Movie, Long>, PagingAndSortingRepository< Movie, Long> { } 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 37
  36. Spring Data REST: JSON Result { _links: { self: {

    href: "http://localhost:8080/api/movies" } }, _embedded: { movies: [ { title: "The Shawshank Redemption", year: „1994", _links: { self: { href: "http://localhost:8080/api/movies/1" }, … 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 38
  37. Spring Data REST Root API 4/25/2024 © Kai Tödter, Licensed

    under a Creative Commons Attribution 4.0 International License. 39 { "_links": { "movies": { "href": "http://localhost:8080/api/movies{?page,size,sort}", "templated": true }, "directors": { "href": "http://localhost:8080/api/directors{?page,size,sort}", "templated": true }, "profile": { "href": "http://localhost:8080/api/profile" } } }
  38. 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 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 40
  39. HAL Explorer 4/25/2024 © Kai Tödter, Licensed under a Creative

    Commons Attribution 4.0 International License. 41
  40. 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 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 42
  41. Controversial Discussion ▪ Are we there yet? ▪ RESTistential Crises

    ▪ http://www.infoq.com/news/2014/03/rest-at- odds-with-web-apis ▪ DHH, Getting hyper about hypermedia apis ▪ https://signalvnoise.com/posts/3373-getting- hyper-about-hypermedia-apis 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 43
  42. Demo 4/25/2024 © Kai Tödter, Licensed under a Creative Commons

    Attribution 4.0 International License. 44
  43. Lab 2: Task 1 ▪ Open lab2/complete in your IDE

    ▪ Run Application.java ▪ Open browser with localhost:8080/api 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 45
  44. Lab 2: Task 2 ▪ Open lab2/initial in your IDE

    ▪ Change the movie repository ▪ Run the application and open your browser with localhost:8080/api ▪ Optional: Write some tests! ▪ Get some ideas from ../complete 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 46
  45. 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/ 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 48
  46. 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> 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 50
  47. 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 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 51
  48. 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! 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 52
  49. 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 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 53
  50. 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution

    4.0 International License. 54 Representation Models
  51. Representation Models ▪ REST => Representational State Transfer ▪ Manipulation

    of resources through their representations ▪ Domain Model != Representation Model ▪ Spring HATEOAS provides RepresentationModel abstraction 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 55
  52. 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 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 56
  53. Domain Model Example public class Director { private Long id;

    private String name; public Director(String name) { this.name = name; } … } 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 57
  54. 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()); } 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 58
  55. Response in HAL Media Type { "id": 2, "name": "Frank

    Darabont", "_links": { "self": { "href": "http://localhost:8080/api/directors/2" } } } 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 59
  56. “ 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) 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 61
  57. 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 ▪ … 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 62
  58. 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution

    4.0 International License. 63 HAL-FORMS Image Source: http://wallpoper.com/images/00/26/43/92/hal-9000_00264392.jpg Shutdown! Restart
  59. HAL-FORMS ▪ Designed to provide forms support for HAL ▪

    Created by Mike Amundsen ▪ _templates for possible actions ▪ Spec: https://rwcbook.github.io/hal-forms/ 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 64
  60. “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.” 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 65 Mike Amundsen Source: https://rwcbook.github.io/hal-forms/
  61. Rendering with HAL-FORMS "_templates": { "default": { "method": "POST", "properties":

    [ { "name": "imdbId", "type": "text" }, { "name": "rank", "type": "number" }, { "name": "rating", "type": "number" }, { "name": "title", "required": true, "type": "text" }, { "name": "year", "type": "number" } ], "target": "http://localhost:8080/api/movies" } … © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 66
  62. Demo 4/25/2024 © Kai Tödter, Licensed under a Creative Commons

    Attribution 4.0 International License. 67
  63. Lab 3: Task 1 ▪ Open lab3/complete in your IDE

    ▪ Run Application.java ▪ Open browser with localhost:8080/api 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 68
  64. Lab 3: Task 2 ▪ Open lab3/initial in your IDE

    ▪ Edit MovieController.java ▪ Implement the method findAll ▪ Add an affordance to create a movie ▪ If time, implement method findOne ▪ Run the application and open your browser with localhost:8080/api 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 69
  65. JSON:API for Spring HATEOAS ▪ Open-Source Project ▪ Apache 2

    License ▪ https://github.com/toedter/spring-hateoas- jsonapi ▪ Reference Documentation ▪ API Documentation 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 71
  66. Domain Model Example public class Director { private Long id;

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

    "type": "directors", "attributes": { "name": "Frank Darabont" } }, "links": { "self": "http://localhost:8080/api/directors/2" } } 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 75
  68. 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 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 77
  69. Example with Annotations public class Movie { @Id private String

    myId; @JsonApiType private String myType; @JsonApiMeta private String myMeta; private String title; } 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 78
  70. 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" } } } 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 79
  71. JsonApiBuilder Movie movie = new Movie("1", "Star Wars"); final RepresentationModel<?>

    jsonApiModel = jsonApiModel() .model(movie) .build(); 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 81
  72. Relationships ▪ In JSON:API, relationships between REST resources are made

    explicit, using the relationship object ▪ Relationships can be to-one or to-many ▪ Relationships must contain at least one of: ▪ links: a links object containing at least one of the following: ▪ self: a link for the relationship itself ▪ related: a related resource link ▪ data: resource linkage with id and type ▪ meta: meta object that contains non-standard meta- information about the relationship 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 83
  73. Build Relationships Movie movie = new Movie("1", "Star Wars"); Director

    director = new Director("1", "George Lucas"); final RepresentationModel<?> jsonApiModel = jsonApiModel() .model(movie) .relationship("directors", director) .build(); 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 84
  74. Relationsship Example { "data": { "id": "1", "type": "movies", "attributes":

    { "title": "Star Wars" }, "relationships": { "directors": { "data": { "id": "1", "type": "directors" } } } } } 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 85
  75. Inclusion of Related Resources ▪ With included, you can include

    the content of related recourses in the compound document ▪ The JsonApiBuilder supports adding ▪ A single included resource ▪ A collection of included resources ▪ The builder assures that included resources with same id and type appear only ONCE 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 87
  76. Inclusion Example for (Movie movie : pagedResult.getContent()) { jsonApiModelBuilder.included(movie.getDirectors()); }

    "included": [ { "id": "1", "type": "directors", "attributes": { "name": "Lana Wachowski" } }, … 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 88
  77. Sparse Fieldsets Convenient way to specify which ▪ Attributes of

    Resources ▪ Relationships (by name) ▪ Attributes of included Relationships will be included in the JSON response 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 89
  78. Controller for Sparse Fieldset In a REST controller, a method

    with HTTP-mapping could provide an optional request attribute for each sparse fieldset @GetMapping("/movies") public ResponseEntity<RepresentationModel<?>> findAll( @RequestParam(value = "included", required = false) String[] included, @RequestParam(value = "fields[movies]", required = false) String[] fieldsMovies) { 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 90
  79. 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution

    4.0 International License. 91 Sparse Fieldsets Demo
  80. Meta ▪ JSON:API Meta can be added using the builder

    or by using the @JsonApiMeta annotation ▪ Paging information Meta can be added automatically => Use PagedModel 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 92
  81. Pagination Example … "links": { "self": "http://localhost/movies", "first": "http://localhost/movies?page[number]=0&page[size]=2", "prev":

    "http://localhost/movies?page[number]=0&page[size]=2", "next": "http://localhost/movies?page[number]=2&page[size]=2", "last": "http://localhost/movies?page[number]=49&page[size]=2" }, "meta": { "page": { "number": 1, "size": 2, "totalPages": 50, "totalElements": 100 } } 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 93
  82. Configuration (1) You can configure ▪ If the JSON:API version

    should be rendered automatically, the default is false. ▪ If JSON:API types should be rendered as pluralized or non pluralized class names. ▪ The default is pluralized ▪ If JSON:API types should be rendered as lower cased or original class names. ▪ The default is lower cased ▪ If page information of a PagedModel should be rendered automatically as JSON:API meta object. ▪ The default is true 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 95
  83. Configuration (2) You can configure ▪ If a specific Java

    class should be rendered with a specific JSON:API type. ▪ A lambda expression to add additional configuration to the Jackson ObjectMapper used for serialization. ▪ Experimental: Render Spring HATEOAS affordances as JSON:API link meta. 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 96
  84. Configuration Example @Bean JsonApiConfiguration jsonApiConfiguration() { return new JsonApiConfiguration() .withJsonApiVersionRendered(true)

    .withPluralizedTypeRendered(false) .withLowerCasedTypeRendered(false) .withTypeForClass(MyMovie.class, "my-movies") .withObjectMapperCustomizer( objectMapper -> objectMapper.configure( SerializationFeature .WRITE_DATES_AS_TIMESTAMPS, true)); } 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 97
  85. Error Handling To create JSON:API compliant error messages, you can

    use JsonApiErrors and JsonApiError return ResponseEntity.badRequest().body( JsonApiErrors.create().withError( JsonApiError.create() .withAboutLink("http://movie-db.com/problem") .withTitle("Movie-based problem") .withStatus(HttpStatus.BAD_REQUEST.toString()) .withDetail("This is a test case"))); 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 98
  86. Error Example { "errors": [ { "links": { "about": "http://movie-db.com/problem"

    }, "status": "400 BAD_REQUEST", "title": "Movie-based problem", "detail": "This is a test case" } ] } 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 99
  87. 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. 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 100
  88. Spring HATEOAS Affordances Example © Kai Tödter, Licensed under a

    Creative Commons Attribution 4.0 International License. 102 final Affordance newMovieAffordance = afford(methodOn(MovieController.class).newMovie(null)); Link selfLink = linkTo(MovieController.class).slash("movies" + uriParams + "page[number]=" + pagedResult.getNumber() + "&page[size]=" + pagedResult.getSize()) .withSelfRel() .andAffordance(newMovieAffordance);
  89. Rendered Affordance (1) 4/25/2024 © Kai Tödter, Licensed under a

    Creative Commons Attribution 4.0 International License. 103 "links": { "self": { "href": "http://localhost:8080/api/movies?page[number]=0... "meta": { "affordances": [ { "name": "newMovie", "link": { "rel": "newMovie", "href": "http://localhost:8080/api/movies" }, "httpMethod": "POST", ...
  90. Rendered Affordance (2) 4/25/2024 © Kai Tödter, Licensed under a

    Creative Commons Attribution 4.0 International License. 104 "inputProperties": [ { "name": "imdbId", "type": "text" }, … { "name": "title", "type": "text", "required": true }, … ]
  91. Lab 4: Task 1 ▪ Open lab4/complete in your IDE

    ▪ Run Application.java ▪ Open browser with localhost:8080/api/movies 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 105
  92. Lab 4: Task 2 ▪ Open lab4/initial in your IDE

    ▪ Edit Application.java ▪ Add JSON:API configuration ▪ Edit MovieController.java ▪ Implement the method findAll ▪ Add an affordance to create a movie ▪ Run the application and open your browser with localhost:8080/api 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 106
  93. OAuth 2.1 ▪ Replaces and obsoletes OAuth 2.0 ▪ Defines

    4 roles: ▪ Resource Owner (RO) ▪ Resource Server (RS) ▪ Client ▪ Authorization Server (AS) ▪ Current Draft: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-10 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 108
  94. OAuth2 Roles Resource Owner: An entity capable of granting access

    to a protected resource. When the resource owner is a person, it is referred to as an end- user. Resource Server: The server hosting the protected resources, capable of accepting and responding to protected resource requests using access tokens. The resource server is often accessible via an API. Client: An application making protected resource requests on behalf of the resource owner and with its authorization. Authorization Server: The server issuing access tokens to the client after successfully authenticating the resource owner and obtaining authorization. 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 109
  95. OAuth2 Flows 4/25/2024 © Kai Tödter, Licensed under a Creative

    Commons Attribution 4.0 International License. 110 Client Resource Server Authorization Server Authorization Grant Access Token Access Token Protected Resource
  96. Client Credential Flow ▪ Resource Owner provides client with ▪

    Client Id ▪ Client Secret ▪ URL to get the access token ▪ Optional: Audience 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 111
  97. Bearer Token ▪ A Bearer Token is a security token

    with the property that any party in possession of the token (a "bearer") can use the token in any way that any other party in possession of it can. Using a Bearer Token does not require a bearer to prove possession of cryptographic key material (proof-of-possession). ▪ We are using the JSON Web Token (JWT) format ▪ See https://datatracker.ietf.org/doc/html/rfc7519 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 112
  98. JWT Example 4/25/2024 © Kai Tödter, Licensed under a Creative

    Commons Attribution 4.0 International License. 113 { "sub": "movie-client", "aud": "movies-audience", "nbf": 1710065429, "scope": [ "movies.read" ], "iss": "http://localhost:9000", "exp": 1710065729, "iat": 1710065429, "jti": "10c15243-210e-4fa0-b39f-07d411472030" }
  99. JWT properties ▪ sub: subject ▪ Whom the token refers

    to ▪ aud: audience ▪ Who or what the token is intended for ▪ nvb: not valid before ▪ Seconds since Unix Epoch ▪ iss: issuer ▪ Who created and signed this token ▪ exp: expiration time ▪ Seconds since Unix Epoch ▪ iat: issued at ▪ Seconds since Unix Epoch ▪ jti: JWT Id ▪ Unique identifier for this token 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 114
  100. JWT Transport ▪ JWT is (usually) not encrypted ▪ JWT

    is always signed with private key owned by issuer (Authorization Server) ▪ Authorization Server provides public key to verify the signature ▪ Use https://jwt.io to decode JWTs 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 115
  101. Spring Authorization Server ▪ https://spring.io/projects/spring-authorization-server ▪ Framework that provides implementations

    of the OAuth 2.1 and OpenID Connect 1.0 specifications and other related specifications ▪ It is built on top of Spring Security 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 116
  102. Spring Authorization Server Config 4/25/2024 © Kai Tödter, Licensed under

    a Creative Commons Attribution 4.0 International License. 117 spring: security: user: name: user password: password oauth2: authorizationserver: client: movie-client: registration: client-id: "movie-client" client-secret: "{noop}secret" client-authentication-methods: - "client_secret_post" authorization-grant-types: - "client_credentials" scopes: - "openid" - "profile" - "movies.read" require-authorization-consent: true
  103. Client Credential Call ▪ POST to http://localhost:9000/oauth2/token ▪ x-www-form-urlencoded body

    ▪ client_id: movie-client ▪ client_secret: secret ▪ scope: movies.read ▪ grant_type: client_credentials 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 118
  104. Client Credentials Call Result 4/25/2024 © Kai Tödter, Licensed under

    a Creative Commons Attribution 4.0 International License. 119 { "access_token": "eyJraWQiO … WFlbJQNo8Q", "scope": "movies.read", "token_type": "Bearer", "expires_in": 300 }
  105. Important URLs ▪ OpenID configuration: ▪ http://localhost:9000/.well-known/openid-configuration ▪ Public Keys:

    ▪ http://localhost:9000/oauth2/jwks 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 120
  106. Lab 5: Task 1 ▪ Open lab5/complete/spring.authorization- server in your

    IDE ▪ Run DefaultAuthorizationServerApplication ▪ Get an access token using client credential flow ▪ You can use the Postman collection 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 121
  107. Spring Security OAuth 4/25/2024 © Kai Tödter, Licensed under a

    Creative Commons Attribution 4.0 International License. 122
  108. Spring Security Configuration (Java) 4/25/2024 © Kai Tödter, Licensed under

    a Creative Commons Attribution 4.0 International License. 123 @Configuration @EnableWebSecurity public class OAuth2ResourceServerSecurityConfiguration { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authorize -> authorize .requestMatchers(HttpMethod.GET, "/api/movies/**").hasAuthority("SCOPE_movies.read") .requestMatchers(HttpMethod.POST, "/api/movies/**").hasAuthority("SCOPE_movies.write") .anyRequest().authenticated() ) .oauth2ResourceServer(oauth2 -> oauth2.jwt(withDefaults())); return http.build(); } }
  109. Spring Security Config (Properties) 4/25/2024 © Kai Tödter, Licensed under

    a Creative Commons Attribution 4.0 International License. 124 spring: security: oauth2: resourceserver: jwt: jwk-set-uri: http://localhost:9000/oauth2/jwks issuer-uri: http://localhost:9000 audiences: movies-audience
  110. Lab 5: Task 2 ▪ Start Spring Authorization Server ▪

    Get an access token ▪ Open lab5/complete in your IDE ▪ Run Application.java ▪ Make a GET request to http://localhost:8080/api/movies => 401 ▪ Add access token with request header ▪ Authorization: Bearer <access token> => 200 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 125
  111. Lab 5: Task 3 ▪ Open lab5/initial in your IDE

    ▪ Edit OAuth2ResourceServerSecurityConfiguration.java ▪ Implement method securityFilterChain ▪ Add security config to application.yml ▪ Call movies endpoint with and without access token 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 126
  112. Lab 5: Task 4 (Optional) ▪ Use Keycloak as Authorization

    Server ▪ Take a look at lab5/keycloak ▪ Start Keycloak in Docker container ▪ Windows: docker-run.bat ▪ Linux: docker-run.sh ▪ Repeat task 3 with Keycloak ▪ Keycloaks jwks URI is http://localhost:9000/auth/realms/movies/protocol/o penid-connect/certs 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 127
  113. 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution

    4.0 International License. 128 Congratulations!
  114. License ▪ This work is licensed under a Creative Commons

    Attribution 4.0 International License. ▪ See http://creativecommons.org/licenses/by/4.0/ 4/25/2024 © Kai Tödter, Licensed under a Creative Commons Attribution 4.0 International License. 130