Wie soll man das denn nutzen? - Spring REST Docs

34ecacd077244d141a23c46ea094df5c?s=47 Gerrit Meier
September 30, 2016

Wie soll man das denn nutzen? - Spring REST Docs

REST API Dokumentation mit Spring REST Docs

34ecacd077244d141a23c46ea094df5c?s=128

Gerrit Meier

September 30, 2016
Tweet

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