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

Wie soll man das denn nutzen? - Spring REST Docs

Gerrit Meier
September 30, 2016

Wie soll man das denn nutzen? - Spring REST Docs

REST API Dokumentation mit Spring REST Docs

Gerrit Meier

September 30, 2016
Tweet

More Decks by Gerrit Meier

Other Decks in Programming

Transcript

  1. Wie soll man das denn nutzen? Dokumentation von REST-Schnittstellen mit

    Spring REST Docs Gerrit Meier@JUG Saxony Day 2016
  2. „Eine schöne RESTful-API haben Sie da, wäre ja traurig, wenn

    die keiner nutzen 
 würde.“
  3. Problem: keine Dokumentation vorhanden

  4. Lösung: Dokumentation nachholen

  5. https://www.flickr.com/photos/whateverjamesinstitches/4623922729/

  6. Senior Consultant
 T-Systems on site services GmbH 8 Jahre ‚professionell‘

    Java JUG Ostfalen Co-Organisator Podcast meistermeier
  7. Gibt es da nicht schon etwas?

  8. Swagger

  9. None
  10. @ApiOperation(nickname = "loginUser",
 value = "Logs user into the system",

    response = classOf[String], 
 httpMethod = "GET")
 @ApiResponses(Array(
 new ApiResponse(code = 400, message = "Invalid username and password combination")))
 def loginUser(
 @ApiParam(value = "The user name for login", required = true)
 username: String,
 @ApiParam(value = "The password for login in clear text", required = true) 
 password: String) = Action { 
 implicit request =>
 JsonResponse("logged in user session:" + System.currentTimeMillis())
 }
  11. 
 @ApiOperation(nickname = "updateUser",
 value = "Updated user“, notes =

    "This can only be done by the logged in user.", httpMethod = "PUT")
 @ApiResponses(Array(
 new ApiResponse(code = 400, message = "Invalid username supplied"),
 new ApiResponse(code = 404, message = "User not found")))
 @ApiImplicitParams(Array(
 new ApiImplicitParam (name = "username", value = "name that need to be 
 updated", required = true, dataType = "String", paramType = "path"),
 new ApiImplicitParam(name = "body", value = "Updated user object",
 required = true, dataType = "models.User", paramType = "body")))
 def updateUser(username: String) = Action { implicit request =>
 request.body.asJson match {
 case Some(e) => {
 val user = Json.mapper.readValue(e.toString, classOf[User])
 userData.addUser(user)
 JsonResponse(user)
 }
 case None => JsonResponse(new value.ApiResponse(400, "Invalid input"))
 }
 }
  12. https://www.flickr.com/photos/endless_autumn/2820524593

  13. Das Problem von Dokumentation am 
 Code ist, dass sie

    veralten wird.
  14. @ApiResponses(
 value = {
 @ApiResponse(code = 200, message = "leaking

    resource available"),
 @ApiResponse(code = 404, message = "cannot find leaking resource"),
 }
 )
 public Status getLeakingInformation() {
 return new Status(200);
 }
  15. @ApiResponses(
 value = {
 @ApiResponse(code = 200, message = "leaking

    resource available"),
 @ApiResponse(code = 404, message = "cannot find leaking resource"),
 }
 )
 public Status getLeakingInformation() {
 return new Status(451);
 }
  16. None
  17. http://martinfowler.com/articles/richardsonMaturityModel.html The Swamp of POX Resources HTTP Verbs Hypermedia Controls

  18. None
  19. Spring REST Docs

  20. None
  21. {
 "_links" : {
 "breweries" : {
 "href" : "http://localhost:8888/breweries"


    },
 "beers" : {
 "href" : "http://localhost:8888/beers"
 },
 "profile" : {
 "href" : "http://localhost:8888/profile"
 }
 }
 } $ curl 'http://localhost:8080/' -i
  22. @Test
 public void index() throws Exception {
 mockMvc.perform(RestDocumentationRequestBuilders.get(„/")) .andExpect(MockMvcResultMatchers.status().isOk())
 .andDo(

    document("index-page", links(
 linkWithRel("breweries").
 description("The <<resources-breweries,breweries resource>>“),
 linkWithRel("beers").description("The <<resources-beers,Beers resource>>"),
 linkWithRel("profile").description("The ALPS profile for the service")
 ), responseFields( fieldWithPath("_links")
 .description("<<resources-index-links,Links>> to other resources“) )
 ));
 }
  23. @Test
 public void index() throws Exception {
 mockMvc.perform(RestDocumentationRequestBuilders.get(„/")) .andExpect(MockMvcResultMatchers.status().isOk())
 .andDo(

    document("index-page", links(
 linkWithRel("breweries").
 description("The <<resources-breweries,breweries resource>>“),
 linkWithRel("beers").description("The <<resources-beers,Beers resource>>"),
 linkWithRel("profile").description("The ALPS profile for the service")
 ), responseFields( fieldWithPath("_links")
 .description("<<resources-index-links,Links>> to other resources“) )
 ));
 }
  24. @Test
 public void index() throws Exception {
 mockMvc.perform(RestDocumentationRequestBuilders.get(„/")) .andExpect(MockMvcResultMatchers.status().isOk())
 .andDo(

    document("index-page", links(
 linkWithRel("breweries").
 description("The <<resources-breweries,breweries resource>>“),
 linkWithRel("beers").description("The <<resources-beers,Beers resource>>"),
 linkWithRel("profile").description("The ALPS profile for the service")
 ), responseFields( fieldWithPath("_links")
 .description("<<resources-index-links,Links>> to other resources“) )
 ));
 }
  25. None
  26. None
  27. None
  28. None
  29. None
  30. None
  31. None
  32. include::

  33. None
  34. DEMO

  35. meistermeier https://projects.spring.io/spring-restdocs/ https://github.com/spring-projects/spring-restdocs https://github.com/meistermeier/spring-rest-docs-sample