Documenting RESTful APIs with Spring REST Docs By Jenn Strater @codeJENNerator 1
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Notes For Those Viewing These Slides Online • Bulleted text like this indicates the key points mentioned on a previous slide. They may not have been included in the official presentation. • If this view does not support links, the links will work in the pdf. In speakerdeck, you can click the ‘download pdf’ button at the right. X
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Outline • API Documentation Background • Approaches to Documentation • Considerations 2 • Test-Driven Documentation • Spring REST Docs • Examples
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Follow Along https://speakerdeck.com/jlstrater/test-driven-docs-springone-2017 https://github.com/jlstrater/groovy-spring-boot-restdocs-example https://github.com/ratpack/example-books https://github.com/jlstrater/spring-restdocs-public-api-example 3
About Me
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Follow Along https://speakerdeck.com/jlstrater/test-driven-docs-springone-2017 https://github.com/jlstrater/groovy-spring-boot-restdocs-example https://github.com/ratpack/example-books https://github.com/jlstrater/spring-restdocs-public-api-example 5
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 6
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ About Me • Co-founder of Gr8Ladies and talk about women in the Groovy Community all over the world • Passionate about bring new people into the Groovy community through free introductory workshops called Gr8Workshops. • Senior Engineer at Zenjob as of June 2017. We’re hiring! zenjob.de/careers • Spent the 2016-2017 academic year in Copenhagen working on OSS and taking classes through a Fulbright Grant. • Prior to the Fulbright Grant, I was a senior consultant at Object Partners, Inc. in Minneapolis, MN, USA. My work with Spring REST Docs started on a project at my client through them. X
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Audience Background • Creating RESTful APIs • Spring Boot • Grails • Ratpack 7 • API Documentation • Wiki Pages, Word Documents, Confluence, etc • Asciidoc / Asciidoctor • Swagger / RAML
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 8 src: https://flic.kr/p/rehEf5
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 8 src: https://flic.kr/p/rehEf5 I hate writing documentation!*
Case Study
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ REST Maturity Model 10 src: http://martinfowler.com/articles/richardsonMaturityModel.html
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ REST Maturity Model 10 src: http://martinfowler.com/articles/richardsonMaturityModel.html
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ REST Maturity Model • I’m not really a fan of the right vs wrong REST debate, but I like this categorization of APIs. • Most of our APIS were level one or two, but we wanted to have the flexibility to use hypermedia • Spring REST docs includes support for level 3 / hypermedia • Swagger 2.0 did not support hypermedia. Swagger 3.0 (released end of July 2017) now does X
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 11 Attribution: @Alvaro_Sanchez
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Monolith vs Microservices As architecture evolves, many companies move from a central monolith to micro services or maybe even gateways and multi-tiered architectures. • For documentation, it was important to have: • a consistent look and feel • a way to show how the services can work together X
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Central Information 12 Security Http Verbs Error Handling Http Status
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Central Information Central Information • For example, security tokens, patterns for error messages, http verbs/status codes, etc • This information needs to be written out and defined once; not on every endpoint. X
Document Design
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 14
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 15
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Central Information Who’s seen this before? Of the people who have never used swagger before, how many understand what this means? Even our CTO who is technical, didn’t want to spend time figuring it out. Also, product teams. This is a swagger ui example but the concept is not limited to Swagger. I have seen many different APIs document in this way. It’s not just URI centric, but also very developer centric. No matter whether you leave here choosing Swagger or Spring REST Docs, think about your users! This is an example from Spring Rest Docs using Asciidoc. Notice the very different way of organizing information on the second slide. Resource centric document design organizes information by topic and includes urls in the examples only. The information from generated solutions isn’t enough. We need the handwritten information too! X
Available Tools
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 17
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 17 Definitions Swagger (OpenAPI Specification) RAML
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 17 Definitions Swagger (OpenAPI Specification) RAML Documentation AsciiDoc Markdown Wikis
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 17 Definitions Swagger (OpenAPI Specification) RAML Documentation AsciiDoc Markdown Wikis Swagger UI Swagger2Markup
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 17 Definitions Swagger (OpenAPI Specification) RAML Testing MockMVC RestAssured Documentation AsciiDoc Markdown Wikis Swagger UI Swagger2Markup
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 17 Definitions Swagger (OpenAPI Specification) RAML Testing MockMVC RestAssured Documentation AsciiDoc Markdown Wikis Swagger UI Swagger2Markup AssertJ- Swagger Contract-First
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 17 Definitions Swagger (OpenAPI Specification) RAML Testing MockMVC RestAssured Documentation AsciiDoc Markdown Wikis Swagger UI Swagger2Markup Spring REST Docs AssertJ- Swagger Contract-First
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 17 Definitions Swagger (OpenAPI Specification) RAML
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 18
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 18
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Swagger Swagger is: — a lot of things • At the core, it is a way to standardize and define HTTP APIs over RPC. • It is very popular because of the many plugins built on top of it for things such as generating client libraries, generating docs, and much more. • In earlier versions, it did not support hypermedia. Documenting across micro services was possible, but required a bit of setup. Depending on the library, some central information is duplicated. X
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Body Slide - Dark Background All body text is Proxima Nova Regular • Subhead (18pt) • Level Two (18pt) • Level Three (18pt) • Level Four (18pt) Use the “Decrease/Increase Indent” 
 tools to change bullet levels • Click on the Home ribbon, Paragraph tab Line spacing is set in master slides 19 Automation img src: https://flic.kr/p/eduUfU
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Body Slide - Dark Background All body text is Proxima Nova Regular • Subhead (18pt) • Level Two (18pt) • Level Three (18pt) • Level Four (18pt) Use the “Decrease/Increase Indent” 
 tools to change bullet levels • Click on the Home ribbon, Paragraph tab Line spacing is set in master slides 20 img src: https://www.flickr.com/photos/ 24874528@N04/17125924230 SpringFox
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ SpringFox SpringFox: • Generates a Swagger Specification from source • Is very easy to setup (in simple cases) • No OpenAPI Spec 3.0 support! X
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Custom Swagger Specification 21 { "swagger": "2.0", "info": { "version": "1", "title": "My Service", "contact": { "name": "Company Name" }, "license": {} }, "host": "example.com", "basepath": "/docs" }
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Swagger UI 22
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 23
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ SpringFox UI approaches • Use SpringFox library • Copy static files and customize X
Considerations
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Customization 25 img src: http://sergiodelamo.es/how-to-secure-your-grails-3-api-with-spring-security-rest-for-grails/
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Customization • For any non-standard configuration, you may have to override the UI. • As one example, we were adding custom headers for oauth jwt tokens. At the time, it was not supported with springfox-ui. X
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Object Mapping 26 img src: https://github.com/springfox/springfox/issues/281
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 27 https://github.com/swagger-api/swagger-core/issues/97
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Customization • In Swagger/OpenAPI Spec 2.0, there was no hypermedia support. • In OpenAPI Spec 3.0, there is some support for links X
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 1 @Secured(‘ROLE_ALLOWED_TO_PERFORM_ACTION’)
 2 @RequestMapping(value = '/v1/serviceName/actionName', method = 3 RequestMethod.POST)
 4 @ApiOperation(value = '/actionName',
 5 notes = 'Enables or disables setting via "1" or "0", respectively')
 6 @ApiResponses(value = [
 7 @ApiResponse(code = 200, response = CustomSettingResponse, message = 8 ‘Successful setting update'),
 9 @ApiResponse(code = 400, response = ErrorResponse, message = 'Invalid 10 user input'),
 11 @ApiResponse(code = 500, response = ErrorResponse, message = 'Unexpected 12 server error')
 13 ])
 14 CustomSettingResponse setSetting(@RequestBody CustomModel settingsValue) {
 15 SaveSettingUpdateRequest request = new SaveSettingUpdateRequest (
 16 settingsValue.fieldOne,
 17 [new TransformedSetting(SettingEnum.POSSIBLE_ENUM_VALUE, 18 new Double(settingsValue.value))]
 19 )
 20 api.saveUpdatedSetting(request)
 21 }
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 1 @Secured(‘ROLE_ALLOWED_TO_PERFORM_ACTION’)
 2 @RequestMapping(value = '/v1/serviceName/actionName', method = 3 RequestMethod.POST)
 4 @ApiOperation(value = '/actionName',
 5 notes = 'Enables or disables setting via "1" or "0", respectively')
 6 @ApiResponses(value = [
 7 @ApiResponse(code = 200, response = CustomSettingResponse, message = 8 ‘Successful setting update'),
 9 @ApiResponse(code = 400, response = ErrorResponse, message = 'Invalid 10 user input'),
 11 @ApiResponse(code = 500, response = ErrorResponse, message = 'Unexpected 12 server error')
 13 ])
 14 CustomSettingResponse setSetting(@RequestBody CustomModel settingsValue) {
 15 SaveSettingUpdateRequest request = new SaveSettingUpdateRequest (
 16 settingsValue.fieldOne,
 17 [new TransformedSetting(SettingEnum.POSSIBLE_ENUM_VALUE, 18 new Double(settingsValue.value))]
 19 )
 20 api.saveUpdatedSetting(request)
 21 } Annotation Hell
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 1 @Secured(‘ROLE_ALLOWED_TO_PERFORM_ACTION’)
 2 @RequestMapping(value = '/v1/serviceName/actionName', method = 3 RequestMethod.POST)
 4 @ApiOperation(value = '/actionName',
 5 notes = 'Enables or disables setting via "1" or "0", respectively')
 6 @ApiResponses(value = [
 7 @ApiResponse(code = 200, response = CustomSettingResponse, message = 8 ‘Successful setting update'),
 9 @ApiResponse(code = 400, response = ErrorResponse, message = 'Invalid 10 user input'),
 11 @ApiResponse(code = 500, response = ErrorResponse, message = 'Unexpected 12 server error')
 13 ])
 14 CustomSettingResponse setSetting(@RequestBody CustomModel settingsValue) {
 15 SaveSettingUpdateRequest request = new SaveSettingUpdateRequest (
 16 settingsValue.fieldOne,
 17 [new TransformedSetting(SettingEnum.POSSIBLE_ENUM_VALUE, 18 new Double(settingsValue.value))]
 19 )
 20 api.saveUpdatedSetting(request)
 21 } Annotation Hell
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 1 @Secured(‘ROLE_ALLOWED_TO_PERFORM_ACTION’)
 2 @RequestMapping(value = '/v1/serviceName/actionName', method = 3 RequestMethod.POST)
 4 @ApiOperation(value = '/actionName',
 5 notes = 'Enables or disables setting via "1" or "0", respectively')
 6 @ApiResponses(value = [
 7 @ApiResponse(code = 200, response = CustomSettingResponse, message = 8 ‘Successful setting update'),
 9 @ApiResponse(code = 400, response = ErrorResponse, message = 'Invalid 10 user input'),
 11 @ApiResponse(code = 500, response = ErrorResponse, message = 'Unexpected 12 server error')
 13 ])
 14 CustomSettingResponse setSetting(@RequestBody CustomModel settingsValue) {
 15 SaveSettingUpdateRequest request = new SaveSettingUpdateRequest (
 16 settingsValue.fieldOne,
 17 [new TransformedSetting(SettingEnum.POSSIBLE_ENUM_VALUE, 18 new Double(settingsValue.value))]
 19 )
 20 api.saveUpdatedSetting(request)
 21 } Annotation Hell X
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 1 @Secured(‘ROLE_ALLOWED_TO_PERFORM_ACTION’)
 2 @RequestMapping(value = '/v1/serviceName/actionName', method = 3 RequestMethod.POST) 4 CustomSettingResponse setSetting(@RequestBody CustomModel settingsValue) {
 5 SaveSettingUpdateRequest request = new SaveSettingUpdateRequest (
 6 settingsValue.fieldOne,
 7 [new TransformedSetting(SettingEnum.POSSIBLE_ENUM_VALUE, 8 new Double(settingsValue.value))]
 9 )
 10 api.saveUpdatedSetting(request)
 11 }
Swagger Advantages
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 31
“Try it” Button Alternatives
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 33
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 34
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Curl -> curl 'http://localhost:8080/greetings' -i -H 'Content-Type: text/plain' HTTP/1.1 200 X-Application-Context: application:8080 Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Date:Thu, 26 Jan 2017 13:28:19 GMT [{"id":1,"message":"Hello"},{"id":2,"message":"Hi"},{"id":3,"message":"Hola"},{"id":4,"message":"Olá"},{"id":5,"message":"Hej"}] 35
Mix and Match
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 37 Swagger2Markup https://github.com/Swagger2Markup/swagger2markup
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ img src: http://www.elvenspirit.com/elf/wp-content/uploads/2011/10/IMG_3013.jpg FAIL!
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ img src: http://www.elvenspirit.com/elf/wp-content/uploads/2011/10/IMG_3013.jpg FAIL! AssertJ-Swagger https://github.com/RobWin/assertj-swagger
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring Cloud Contract 39
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 40
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 40 Definitions Swagger (OpenAPI Specification) RAML
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 40 Definitions Swagger (OpenAPI Specification) RAML Documentation AsciiDoc Markdown Wikis
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 40 Definitions Swagger (OpenAPI Specification) RAML Documentation AsciiDoc Markdown Wikis Swagger UI Swagger2Markup
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 40 Definitions Swagger (OpenAPI Specification) RAML Testing MockMVC RestAssured Documentation AsciiDoc Markdown Wikis Swagger UI Swagger2Markup
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 40 Definitions Swagger (OpenAPI Specification) RAML Testing MockMVC RestAssured Documentation AsciiDoc Markdown Wikis Swagger UI Swagger2Markup AssertJ- Swagger Contract-First
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 40 Definitions Swagger (OpenAPI Specification) RAML Testing MockMVC RestAssured Documentation AsciiDoc Markdown Wikis Swagger UI Swagger2Markup Spring REST Docs AssertJ- Swagger Contract-First
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Development Green Red Refactor
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Documentation
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Documentation Red
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Documentation Red
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Documentation Document Red
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Documentation Document Red
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Documentation Document Green Red
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Documentation Document Green Red
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Documentation Document Green Red Refactor
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Documentation Document Green Red Refactor
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Winning Solution https://flic.kr/p/5XiKxU Winning Solution
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Winning Solution • Ensures documentation matches implementation • Encourages writing more tests • Reduces duplication in docs and tests • Removes annotations from source X
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs 44 https://flic.kr/p/5XiKxU
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Game Changers 45 https://flic.kr/p/9Tiv3U
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Game Changers •Generated code snippets •Tests fail when documentation is missing or out-of-date •Rest APIs with Hypermedia •Ratpack •Dynamic routing doesn’t work with Swagger X
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ About Spring REST Docs 46
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ About Spring REST Docs projects.spring.io/spring-restdocs 46
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ About Spring REST Docs projects.spring.io/spring-restdocs @springrestdocs 46
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ About Spring REST Docs projects.spring.io/spring-restdocs @springrestdocs https://github.com/spring-projects/spring-restdocs 46
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ About Spring REST Docs •Start with reading the docs; The written docs are good! •Overview •Sponsored by Pivotal •Project Lead - Andy Wilkinson •Current Version - 2.0.0 released Nov 28 •Twitter Account and Official Logo X
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ About Spring REST Docs • Test-Driven Documentation with Spring REST Docs (Java and Spring Boot) - Spring I/O 2016 Andy Wilkinson • Writing comprehensive and guaranteed up-to-date REST API documentation - SpringOne Platform 2016 Anders Evers X
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Out of the Box 47
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Out of the Box Testing Frameworks • MockMVC • RestAssured • WebTestClient - NEW! 47
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Out of the Box Testing Frameworks • MockMVC • RestAssured • WebTestClient - NEW! 47 Build Tools • Gradle • Maven
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Out of the Box 48
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Out of the Box Documentation Format • AsciiDoc • Markdown 48
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Out of the Box Documentation Format • AsciiDoc • Markdown 48 Sample Projects • Spring Boot • Grails • Slate • TestNG • And more!
Examples
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Groovier Spring REST Docs • Spring Boot • Ratpack • Grails 50
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Groovier Spring REST Docs Example - Spring Boot Groovy Spring Boot Project + Asciidoctor Gradle plugin + Spring REST Docs WebTestClient to Spock tests + Add to static assets during build and publish to GitHub pages 51
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 52
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 52
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 52
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Groovier Spring REST Docs Example - Spring Boot • Start with lazybones spring boot app • Add mock endpoints for example https://github.com/jlstrater/groovy-spring-boot-restdocs-example Updated to Spring Boot 2.0.0.M7 and thanks to: https://www.callicoder.com/ reactive-rest-apis-spring-webflux-reactive-mongo/ 53
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 54
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Endpoints @RestController @RequestMapping('/greetings') class GreetingsController { @Autowired GreetingRepository greetingsRepository @PostMapping() Mono<Greeting> createGreeting(@Valid @RequestBody Greeting greeting) { return greetingsRepository.save(greeting) } @GetMapping() Flux<Greeting> listAllGreetings() { return greetingsRepository.findAll() } @GetMapping('/{id}') Mono<Greeting> getGreetingById(@PathVariable(value = 'id') String greetingId) { greetingsRepository.findById(greetingId) } } 55
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Endpoints @RestController @RequestMapping('/greetings') class GreetingsController { @Autowired GreetingRepository greetingsRepository @PostMapping() Mono<Greeting> createGreeting(@Valid @RequestBody Greeting greeting) { return greetingsRepository.save(greeting) } @GetMapping() Flux<Greeting> listAllGreetings() { return greetingsRepository.findAll() } @GetMapping('/{id}') Mono<Greeting> getGreetingById(@PathVariable(value = 'id') String greetingId) { greetingsRepository.findById(greetingId) } } 55 Create a new Greeting
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Endpoints @RestController @RequestMapping('/greetings') class GreetingsController { @Autowired GreetingRepository greetingsRepository @PostMapping() Mono<Greeting> createGreeting(@Valid @RequestBody Greeting greeting) { return greetingsRepository.save(greeting) } @GetMapping() Flux<Greeting> listAllGreetings() { return greetingsRepository.findAll() } @GetMapping('/{id}') Mono<Greeting> getGreetingById(@PathVariable(value = 'id') String greetingId) { greetingsRepository.findById(greetingId) } } 55 Create a new Greeting List all greetings
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Endpoints @RestController @RequestMapping('/greetings') class GreetingsController { @Autowired GreetingRepository greetingsRepository @PostMapping() Mono<Greeting> createGreeting(@Valid @RequestBody Greeting greeting) { return greetingsRepository.save(greeting) } @GetMapping() Flux<Greeting> listAllGreetings() { return greetingsRepository.findAll() } @GetMapping('/{id}') Mono<Greeting> getGreetingById(@PathVariable(value = 'id') String greetingId) { greetingsRepository.findById(greetingId) } } 55 Create a new Greeting List all greetings Get a greeting by id
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 56
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 56
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ AsciiDoc [introduction] = Introduction The Example API is a RESTful web service that shows how Spring REST docs works. [[overview-http-verbs]] == HTTP verbs The Example API tries to adhere as closely as possible to standard HTTP and REST conventions in its use of HTTP verbs. |=== | Verb | Usage | `GET` | Used to retrieve a resource | `POST` | Used to create a new resource | `PUT` | Used to update an existing resource, overwrites all fields 57
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Asciidoctor Gradle Plugin 58
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ AsciiDoc Gradle Configuration apply plugin: 'org.asciidoctor.convert' asciidoctor { backends 'html5' attributes 'source-highlighter' : 'prettify', 'imagesdir':'images', 'toc':'left', 'icons': 'font', 'setanchors':'true', 'idprefix':'', 'idseparator':'-', 'docinfo1':'true', } 59
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 60
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 60
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 62
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 62
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Project Reactor and the WebTestClient 63
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Setup @CompileStatic @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class BaseControllerSpec extends Specification { @Autowired ApplicationContext context protected WebTestClient webTestClient void setup() { this.webTestClient = WebTestClient.bindToApplicationContext(this.context) .configureClient() .baseUrl('/greetings') .build() } } 64
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Setup @CompileStatic @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class BaseControllerSpec extends Specification { @Autowired ApplicationContext context protected WebTestClient webTestClient void setup() { this.webTestClient = WebTestClient.bindToApplicationContext(this.context) .configureClient() .baseUrl('/greetings') .build() } } 64 If context is null, remember to use spock-spring!!
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ WebTestClient Call and Assertions this.webTestClient.post().uri('/') .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .body(BodyInserters.fromObject('{"message": "Hello SpringOne Platform!"}')) .exchange() .expectStatus().isOk() .expectBody() .jsonPath('$.id').isNotEmpty() .jsonPath('$.message').isEqualTo('Hello SpringOne Platform!') 65
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 66
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 66
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs Gradle Configuration dependencies { … testCompile "org.springframework.restdocs:spring-restdocs-webtestclient:${springRestDocsVersion}" asciidoctor "org.springframework.restdocs:spring-restdocs-asciidoctor:${springRestDocsVersion}" } ext { snippetsDir = file('build/generated-snippets') } test { outputs.dir "$projectDir/src/main/resources/public" } asciidoctor { dependsOn test inputs.dir snippetsDir } build { dependsOn asciidoctor } ext['spring-restdocs.version'] = springRestDocsVersion 67
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs with WebTestClient (setup) @CompileStatic @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class BaseControllerSpec extends Specification { @Rule JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation() @Autowired ApplicationContext context protected WebTestClient webTestClient void setup() { this.webTestClient = WebTestClient.bindToApplicationContext(this.context) .configureClient() .baseUrl('/greetings') .filter(documentationConfiguration(restDocumentation)) .build() } } 68
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs with WebTestClient (setup) @CompileStatic @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class BaseControllerSpec extends Specification { @Rule JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation() @Autowired ApplicationContext context protected WebTestClient webTestClient void setup() { this.webTestClient = WebTestClient.bindToApplicationContext(this.context) .configureClient() .baseUrl('/greetings') .filter(documentationConfiguration(restDocumentation)) .build() } } 68
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs with WebTestClient (setup) @CompileStatic @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class BaseControllerSpec extends Specification { @Rule JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation() @Autowired ApplicationContext context protected WebTestClient webTestClient void setup() { this.webTestClient = WebTestClient.bindToApplicationContext(this.context) .configureClient() .baseUrl('/greetings') .filter(documentationConfiguration(restDocumentation)) .build() } } 68
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs with WebTestClient (tests) void 'test and document creating a greeting with a custom name'() { expect: this.webTestClient.post().uri('/') .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .body(BodyInserters.fromObject('{"message": "Hello SpringOne Platform!"}')) .exchange() .expectStatus().isOk() .expectBody() .jsonPath('$.id').isNotEmpty() .jsonPath('$.message').isEqualTo('Hello SpringOne Platform!') .consumeWith(document('greetings-post-example', preprocessRequest(prettyPrint()), requestFields( fieldWithPath('message').type(JsonFieldType.STRING) .description("The greeting's message")))) }` 69
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs with WebTestClient (tests) void 'test and document creating a greeting with a custom name'() { expect: this.webTestClient.post().uri('/') .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .body(BodyInserters.fromObject('{"message": "Hello SpringOne Platform!"}')) .exchange() .expectStatus().isOk() .expectBody() .jsonPath('$.id').isNotEmpty() .jsonPath('$.message').isEqualTo('Hello SpringOne Platform!') .consumeWith(document('greetings-post-example', preprocessRequest(prettyPrint()), requestFields( fieldWithPath('message').type(JsonFieldType.STRING) .description("The greeting's message")))) }` 69
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs with WebTestClient (tests) void 'test and document get of a list of greetings'() { expect: this.webTestClient.get().uri('/').accept(MediaType.APPLICATION_JSON) .exchange() .expectStatus().isOk() .expectBody() .consumeWith(document('greetings-list-example', preprocessResponse(prettyPrint()), responseFields(greetingList))) } FieldDescriptor[] greetingList = new FieldDescriptor().with { [fieldWithPath('[].id').type(JsonFieldType.STRING).optional() .description("The greeting's id"), fieldWithPath('[].message').type(JsonFieldType.STRING) .description("The greeting's message")] } 70
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs with WebTestClient (tests) void 'test and document get of a list of greetings'() { expect: this.webTestClient.get().uri('/').accept(MediaType.APPLICATION_JSON) .exchange() .expectStatus().isOk() .expectBody() .consumeWith(document('greetings-list-example', preprocessResponse(prettyPrint()), responseFields(greetingList))) } FieldDescriptor[] greetingList = new FieldDescriptor().with { [fieldWithPath('[].id').type(JsonFieldType.STRING).optional() .description("The greeting's id"), fieldWithPath('[].message').type(JsonFieldType.STRING) .description("The greeting's message")] } 70
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs with WebTestClient (tests) void 'test and document get of a list of greetings'() { expect: this.webTestClient.get().uri('/').accept(MediaType.APPLICATION_JSON) .exchange() .expectStatus().isOk() .expectBody() .consumeWith(document('greetings-list-example', preprocessResponse(prettyPrint()), responseFields(greetingList))) } FieldDescriptor[] greetingList = new FieldDescriptor().with { [fieldWithPath('[].id').type(JsonFieldType.STRING).optional() .description("The greeting's id"), fieldWithPath('[].message').type(JsonFieldType.STRING) .description("The greeting's message")] } 70
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Error Messages 71
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Error Messages 71
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Error Messages 71
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Error Messages 71
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Error Messages 71
Special Use Case
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 
 +@WebMvcTest(controllers = GreetingsController)
 +@AutoConfigureRestDocs(
 + outputDir = "build/generated-snippets",
 + uriHost = “api.example.com”,
 + uriPort = 8080
 ) class BaseControllerSpec extends Specification { 
 // @Rule
 // JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation('src/docs/generated-snippets')
 
 + @Autowired
 protected MockMvc mockMvc
 //
 // @Autowired
 // private WebApplicationContext context
 //
 // void setup() {
 // this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
 // .apply(documentationConfiguration(this.restDocumentation))
 // .build()
 // } } 73
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 74
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 74
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Generated Snippets 75 By Default When Specified curl-request.adoc response-fields.adoc http-request.adoc request-parameters.adoc httpie-request.adoc request-parts.adoc http-response.adoc path-parameters.adoc request body request-parts.adoc response body
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ http-request.adoc [source,http,options="nowrap"] ---- POST /greetings/ HTTP/1.1 Content-Type: application/json Accept: application/json Host: localhost:8080 Content-Length: 45 { "message" : "Hello SpringOne Platform!" } ---- 76
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ response-fields.adoc |=== |Path|Type|Description |`id` |`String` |The greeting's id |`message` |`String` |The greeting's message |=== 77
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 78
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 79 +
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 79 +
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Adding The Snippets [[overview-errors]] == Errors Whenever an error response (status code >= 400) is returned, the body will contain a JSON object that describes the problem. The error object has the following structure: include::{snippets}/error-example/response-fields.adoc[] For example, a request that attempts to delete on the greetings endpoint will produce a `405 Method Not Allowed` response: operation::error-example[snippets='curl-request,http-request,http-response'] [[resources]] = Resources include::resources/greetings.adoc[] 80
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Adding The Snippets [[overview-errors]] == Errors Whenever an error response (status code >= 400) is returned, the body will contain a JSON object that describes the problem. The error object has the following structure: include::{snippets}/error-example/response-fields.adoc[] For example, a request that attempts to delete on the greetings endpoint will produce a `405 Method Not Allowed` response: operation::error-example[snippets='curl-request,http-request,http-response'] [[resources]] = Resources include::resources/greetings.adoc[] 80
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Adding The Snippets [[overview-errors]] == Errors Whenever an error response (status code >= 400) is returned, the body will contain a JSON object that describes the problem. The error object has the following structure: include::{snippets}/error-example/response-fields.adoc[] For example, a request that attempts to delete on the greetings endpoint will produce a `405 Method Not Allowed` response: operation::error-example[snippets='curl-request,http-request,http-response'] [[resources]] = Resources include::resources/greetings.adoc[] 80
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Adding The Snippets [[overview-errors]] == Errors Whenever an error response (status code >= 400) is returned, the body will contain a JSON object that describes the problem. The error object has the following structure: include::{snippets}/error-example/response-fields.adoc[] For example, a request that attempts to delete on the greetings endpoint will produce a `405 Method Not Allowed` response: operation::error-example[snippets='curl-request,http-request,http-response'] [[resources]] = Resources include::resources/greetings.adoc[] 80
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 81
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 81
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Building the docs . 82 src/docs/ asciidoc index.adoc build/asciidoc/ html5 index.html .gradlew asciidoctor
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
Publishing Strategies
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Publishing Strategies • Hook in asciidoctor with the gradle build task • Run the asciidoctor test separately (but make sure to run AFTER the tests) • Send to static resources directory in the current app or send to a remote site (for example Github Pages X
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 85
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 85 http://api.example.com/docs
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ publish.gradle buildscript { repositories { jcenter() } dependencies { classpath 'org.ajoberstar:gradle-git:1.1.0' } } apply plugin: 'org.ajoberstar.github-pages' githubPages { repoUri = 'git@github.com:jlstrater/groovy-spring-boot-restdocs-example.git' pages { from(file('build/asciidoc/html5')) } } 86
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ publish.gradle buildscript { repositories { jcenter() } dependencies { classpath 'org.ajoberstar:gradle-git:1.1.0' } } apply plugin: 'org.ajoberstar.github-pages' githubPages { repoUri = 'git@github.com:jlstrater/groovy-spring-boot-restdocs-example.git' pages { from(file('build/asciidoc/html5')) } } 86 If you use this method, remember to deploy docs at the same time as the project!
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 87
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 87 http://jlstrater.github.io/groovy- spring-boot-restdocs-example
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 87 http://jlstrater.github.io/groovy- spring-boot-restdocs-example ./gradlew publish
Support for Rest-Assured
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Groovier Spring REST Docs • Ratpack • Grails 89
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Groovier Spring REST Docs Example - Ratpack • Ratpack Example Project • https://github.com/ratpack/example-books • Spring RESTdocs RestAssured • https://github.com/ratpack/example-books/pull/25 92
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Groovier Spring REST Docs Example - Ratpack path(":isbn") {
 def isbn = pathTokens["isbn"]
 
 byMethod {
 get {
 bookService.find(isbn).
 single().
 subscribe { Book book ->
 if (book == null) {
 clientError 404
 } else {
 render book
 }
 }
 } ... }
 } 93 byMethod {
 get {
 bookService.all().
 toList().
 subscribe { List<Book> books ->
 render json(books)
 }
 }
 post {
 parse(jsonNode()).
 observe().
 flatMap { input ->
 bookService.insert(
 input.get("isbn").asText(),
 input.get("quantity").asLong(),
 input.get("price").asDouble()
 )
 }.
 single().
 flatMap {
 bookService.find(it)
 }.
 single().
 subscribe { Book createdBook ->
 render createdBook
 }
 } }
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Groovier Spring REST Docs Example - Ratpack path(":isbn") {
 def isbn = pathTokens["isbn"]
 
 byMethod {
 get {
 bookService.find(isbn).
 single().
 subscribe { Book book ->
 if (book == null) {
 clientError 404
 } else {
 render book
 }
 }
 } ... }
 } 93 byMethod {
 get {
 bookService.all().
 toList().
 subscribe { List<Book> books ->
 render json(books)
 }
 }
 post {
 parse(jsonNode()).
 observe().
 flatMap { input ->
 bookService.insert(
 input.get("isbn").asText(),
 input.get("quantity").asLong(),
 input.get("price").asDouble()
 )
 }.
 single().
 flatMap {
 bookService.find(it)
 }.
 single().
 subscribe { Book createdBook ->
 render createdBook
 }
 } } Get a book by ISBN /api/books/1932394842
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Groovier Spring REST Docs Example - Ratpack path(":isbn") {
 def isbn = pathTokens["isbn"]
 
 byMethod {
 get {
 bookService.find(isbn).
 single().
 subscribe { Book book ->
 if (book == null) {
 clientError 404
 } else {
 render book
 }
 }
 } ... }
 } 93 byMethod {
 get {
 bookService.all().
 toList().
 subscribe { List<Book> books ->
 render json(books)
 }
 }
 post {
 parse(jsonNode()).
 observe().
 flatMap { input ->
 bookService.insert(
 input.get("isbn").asText(),
 input.get("quantity").asLong(),
 input.get("price").asDouble()
 )
 }.
 single().
 flatMap {
 bookService.find(it)
 }.
 single().
 subscribe { Book createdBook ->
 render createdBook
 }
 } } Get a book by ISBN /api/books/1932394842 Get all books /api/books
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Groovier Spring REST Docs Example - Ratpack path(":isbn") {
 def isbn = pathTokens["isbn"]
 
 byMethod {
 get {
 bookService.find(isbn).
 single().
 subscribe { Book book ->
 if (book == null) {
 clientError 404
 } else {
 render book
 }
 }
 } ... }
 } 93 byMethod {
 get {
 bookService.all().
 toList().
 subscribe { List<Book> books ->
 render json(books)
 }
 }
 post {
 parse(jsonNode()).
 observe().
 flatMap { input ->
 bookService.insert(
 input.get("isbn").asText(),
 input.get("quantity").asLong(),
 input.get("price").asDouble()
 )
 }.
 single().
 flatMap {
 bookService.find(it)
 }.
 single().
 subscribe { Book createdBook ->
 render createdBook
 }
 } } Get a book by ISBN /api/books/1932394842 Get all books /api/books Post to create a new book /api/books
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 94 https://github.com/jayway/rest-assured
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ abstract class BaseDocumentationSpec extends Specification {
 
 @Shared
 ApplicationUnderTest aut = new ExampleBooksApplicationUnderTest()
 
 @Rule
 JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation()
 
 protected RequestSpecification documentationSpec
 
 void setup() {
 this.documentationSpec = new RequestSpecBuilder()
 .addFilter(documentationConfiguration(restDocumentation))
 .build()
 }
 } 95
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 96
Documenting Public APIs
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Blog Post https://jennstrater.blogspot.com/2017/01/using-spring-rest-docs-to-document.html 98
Outcomes
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Outcomes • Made it to production! :) • Team was happy with Spring REST Docs • Other dev teams like to see the examples X
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Read the Docs for More On… • Adding Security and Headers • Documenting Constraints • Hypermedia Support • XML Support • Using Markdown instead of Asciidoc • Third Party Extensions for WireMock, Jersey, Spring Cloud Contracts, AutoRestDocs 100
Conclusion
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 102 Definitions Swagger (OpenAPI Specification) RAML Testing MockMVC RestAssured Documentation AsciiDoc Markdown Wikis Swagger UI Swagger2Markup Spring REST Docs AssertJ- Swagger Contract-First
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Conclusion • API documentation is complex • Choosing the right tool for the job not just about the easiest one to setup • Spring REST Docs is a promising tool to enforce good testing and documentation practices without muddying source code. • I still hate writing boilerplate documentation, but at least it’s a little less painful now. X
Unless otherwise indicated, these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Next Steps • Join the Groovy Community on Slack groovycommunity.com • Join #spring-restdocs on gitter https://gitter.im/spring-projects/spring-restdocs 103
Learn More. Stay Connected. https://speakerdeck.com/jlstrater/test-driven-docs-springone-2017 Follow on Twitter @codeJENNerator 104 #springone@s1p

Documenting RESTful APIs with Spring REST Docs

  • 1.
    Documenting RESTful APIswith Spring REST Docs By Jenn Strater @codeJENNerator 1
  • 2.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Notes For Those Viewing These Slides Online • Bulleted text like this indicates the key points mentioned on a previous slide. They may not have been included in the official presentation. • If this view does not support links, the links will work in the pdf. In speakerdeck, you can click the ‘download pdf’ button at the right. X
  • 3.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Outline • API Documentation Background • Approaches to Documentation • Considerations 2 • Test-Driven Documentation • Spring REST Docs • Examples
  • 4.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Follow Along https://speakerdeck.com/jlstrater/test-driven-docs-springone-2017 https://github.com/jlstrater/groovy-spring-boot-restdocs-example https://github.com/ratpack/example-books https://github.com/jlstrater/spring-restdocs-public-api-example 3
  • 5.
  • 6.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Follow Along https://speakerdeck.com/jlstrater/test-driven-docs-springone-2017 https://github.com/jlstrater/groovy-spring-boot-restdocs-example https://github.com/ratpack/example-books https://github.com/jlstrater/spring-restdocs-public-api-example 5
  • 7.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 6
  • 8.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ About Me • Co-founder of Gr8Ladies and talk about women in the Groovy Community all over the world • Passionate about bring new people into the Groovy community through free introductory workshops called Gr8Workshops. • Senior Engineer at Zenjob as of June 2017. We’re hiring! zenjob.de/careers • Spent the 2016-2017 academic year in Copenhagen working on OSS and taking classes through a Fulbright Grant. • Prior to the Fulbright Grant, I was a senior consultant at Object Partners, Inc. in Minneapolis, MN, USA. My work with Spring REST Docs started on a project at my client through them. X
  • 9.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Audience Background • Creating RESTful APIs • Spring Boot • Grails • Ratpack 7 • API Documentation • Wiki Pages, Word Documents, Confluence, etc • Asciidoc / Asciidoctor • Swagger / RAML
  • 10.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 8 src: https://flic.kr/p/rehEf5
  • 11.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 8 src: https://flic.kr/p/rehEf5 I hate writing documentation!*
  • 12.
  • 13.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ REST Maturity Model 10 src: http://martinfowler.com/articles/richardsonMaturityModel.html
  • 14.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ REST Maturity Model 10 src: http://martinfowler.com/articles/richardsonMaturityModel.html
  • 15.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ REST Maturity Model • I’m not really a fan of the right vs wrong REST debate, but I like this categorization of APIs. • Most of our APIS were level one or two, but we wanted to have the flexibility to use hypermedia • Spring REST docs includes support for level 3 / hypermedia • Swagger 2.0 did not support hypermedia. Swagger 3.0 (released end of July 2017) now does X
  • 16.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 11 Attribution: @Alvaro_Sanchez
  • 17.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Monolith vs Microservices As architecture evolves, many companies move from a central monolith to micro services or maybe even gateways and multi-tiered architectures. • For documentation, it was important to have: • a consistent look and feel • a way to show how the services can work together X
  • 18.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Central Information 12 Security Http Verbs Error Handling Http Status
  • 19.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Central Information Central Information • For example, security tokens, patterns for error messages, http verbs/status codes, etc • This information needs to be written out and defined once; not on every endpoint. X
  • 20.
  • 21.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 14
  • 22.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 15
  • 23.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Central Information Who’s seen this before? Of the people who have never used swagger before, how many understand what this means? Even our CTO who is technical, didn’t want to spend time figuring it out. Also, product teams. This is a swagger ui example but the concept is not limited to Swagger. I have seen many different APIs document in this way. It’s not just URI centric, but also very developer centric. No matter whether you leave here choosing Swagger or Spring REST Docs, think about your users! This is an example from Spring Rest Docs using Asciidoc. Notice the very different way of organizing information on the second slide. Resource centric document design organizes information by topic and includes urls in the examples only. The information from generated solutions isn’t enough. We need the handwritten information too! X
  • 24.
  • 25.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 17
  • 26.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 17 Definitions Swagger (OpenAPI Specification) RAML
  • 27.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 17 Definitions Swagger (OpenAPI Specification) RAML Documentation AsciiDoc Markdown Wikis
  • 28.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 17 Definitions Swagger (OpenAPI Specification) RAML Documentation AsciiDoc Markdown Wikis Swagger UI Swagger2Markup
  • 29.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 17 Definitions Swagger (OpenAPI Specification) RAML Testing MockMVC RestAssured Documentation AsciiDoc Markdown Wikis Swagger UI Swagger2Markup
  • 30.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 17 Definitions Swagger (OpenAPI Specification) RAML Testing MockMVC RestAssured Documentation AsciiDoc Markdown Wikis Swagger UI Swagger2Markup AssertJ- Swagger Contract-First
  • 31.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 17 Definitions Swagger (OpenAPI Specification) RAML Testing MockMVC RestAssured Documentation AsciiDoc Markdown Wikis Swagger UI Swagger2Markup Spring REST Docs AssertJ- Swagger Contract-First
  • 32.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 17 Definitions Swagger (OpenAPI Specification) RAML
  • 33.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 18
  • 34.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 18
  • 35.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Swagger Swagger is: — a lot of things • At the core, it is a way to standardize and define HTTP APIs over RPC. • It is very popular because of the many plugins built on top of it for things such as generating client libraries, generating docs, and much more. • In earlier versions, it did not support hypermedia. Documenting across micro services was possible, but required a bit of setup. Depending on the library, some central information is duplicated. X
  • 36.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Body Slide - Dark Background All body text is Proxima Nova Regular • Subhead (18pt) • Level Two (18pt) • Level Three (18pt) • Level Four (18pt) Use the “Decrease/Increase Indent” 
 tools to change bullet levels • Click on the Home ribbon, Paragraph tab Line spacing is set in master slides 19 Automation img src: https://flic.kr/p/eduUfU
  • 37.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Body Slide - Dark Background All body text is Proxima Nova Regular • Subhead (18pt) • Level Two (18pt) • Level Three (18pt) • Level Four (18pt) Use the “Decrease/Increase Indent” 
 tools to change bullet levels • Click on the Home ribbon, Paragraph tab Line spacing is set in master slides 20 img src: https://www.flickr.com/photos/ 24874528@N04/17125924230 SpringFox
  • 38.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ SpringFox SpringFox: • Generates a Swagger Specification from source • Is very easy to setup (in simple cases) • No OpenAPI Spec 3.0 support! X
  • 39.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Custom Swagger Specification 21 { "swagger": "2.0", "info": { "version": "1", "title": "My Service", "contact": { "name": "Company Name" }, "license": {} }, "host": "example.com", "basepath": "/docs" }
  • 40.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Swagger UI 22
  • 41.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 23
  • 42.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ SpringFox UI approaches • Use SpringFox library • Copy static files and customize X
  • 43.
  • 44.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Customization 25 img src: http://sergiodelamo.es/how-to-secure-your-grails-3-api-with-spring-security-rest-for-grails/
  • 45.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Customization • For any non-standard configuration, you may have to override the UI. • As one example, we were adding custom headers for oauth jwt tokens. At the time, it was not supported with springfox-ui. X
  • 46.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Object Mapping 26 img src: https://github.com/springfox/springfox/issues/281
  • 47.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 27 https://github.com/swagger-api/swagger-core/issues/97
  • 48.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Customization • In Swagger/OpenAPI Spec 2.0, there was no hypermedia support. • In OpenAPI Spec 3.0, there is some support for links X
  • 49.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 1 @Secured(‘ROLE_ALLOWED_TO_PERFORM_ACTION’)
 2 @RequestMapping(value = '/v1/serviceName/actionName', method = 3 RequestMethod.POST)
 4 @ApiOperation(value = '/actionName',
 5 notes = 'Enables or disables setting via "1" or "0", respectively')
 6 @ApiResponses(value = [
 7 @ApiResponse(code = 200, response = CustomSettingResponse, message = 8 ‘Successful setting update'),
 9 @ApiResponse(code = 400, response = ErrorResponse, message = 'Invalid 10 user input'),
 11 @ApiResponse(code = 500, response = ErrorResponse, message = 'Unexpected 12 server error')
 13 ])
 14 CustomSettingResponse setSetting(@RequestBody CustomModel settingsValue) {
 15 SaveSettingUpdateRequest request = new SaveSettingUpdateRequest (
 16 settingsValue.fieldOne,
 17 [new TransformedSetting(SettingEnum.POSSIBLE_ENUM_VALUE, 18 new Double(settingsValue.value))]
 19 )
 20 api.saveUpdatedSetting(request)
 21 }
  • 50.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 1 @Secured(‘ROLE_ALLOWED_TO_PERFORM_ACTION’)
 2 @RequestMapping(value = '/v1/serviceName/actionName', method = 3 RequestMethod.POST)
 4 @ApiOperation(value = '/actionName',
 5 notes = 'Enables or disables setting via "1" or "0", respectively')
 6 @ApiResponses(value = [
 7 @ApiResponse(code = 200, response = CustomSettingResponse, message = 8 ‘Successful setting update'),
 9 @ApiResponse(code = 400, response = ErrorResponse, message = 'Invalid 10 user input'),
 11 @ApiResponse(code = 500, response = ErrorResponse, message = 'Unexpected 12 server error')
 13 ])
 14 CustomSettingResponse setSetting(@RequestBody CustomModel settingsValue) {
 15 SaveSettingUpdateRequest request = new SaveSettingUpdateRequest (
 16 settingsValue.fieldOne,
 17 [new TransformedSetting(SettingEnum.POSSIBLE_ENUM_VALUE, 18 new Double(settingsValue.value))]
 19 )
 20 api.saveUpdatedSetting(request)
 21 } Annotation Hell
  • 51.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 1 @Secured(‘ROLE_ALLOWED_TO_PERFORM_ACTION’)
 2 @RequestMapping(value = '/v1/serviceName/actionName', method = 3 RequestMethod.POST)
 4 @ApiOperation(value = '/actionName',
 5 notes = 'Enables or disables setting via "1" or "0", respectively')
 6 @ApiResponses(value = [
 7 @ApiResponse(code = 200, response = CustomSettingResponse, message = 8 ‘Successful setting update'),
 9 @ApiResponse(code = 400, response = ErrorResponse, message = 'Invalid 10 user input'),
 11 @ApiResponse(code = 500, response = ErrorResponse, message = 'Unexpected 12 server error')
 13 ])
 14 CustomSettingResponse setSetting(@RequestBody CustomModel settingsValue) {
 15 SaveSettingUpdateRequest request = new SaveSettingUpdateRequest (
 16 settingsValue.fieldOne,
 17 [new TransformedSetting(SettingEnum.POSSIBLE_ENUM_VALUE, 18 new Double(settingsValue.value))]
 19 )
 20 api.saveUpdatedSetting(request)
 21 } Annotation Hell
  • 52.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 1 @Secured(‘ROLE_ALLOWED_TO_PERFORM_ACTION’)
 2 @RequestMapping(value = '/v1/serviceName/actionName', method = 3 RequestMethod.POST)
 4 @ApiOperation(value = '/actionName',
 5 notes = 'Enables or disables setting via "1" or "0", respectively')
 6 @ApiResponses(value = [
 7 @ApiResponse(code = 200, response = CustomSettingResponse, message = 8 ‘Successful setting update'),
 9 @ApiResponse(code = 400, response = ErrorResponse, message = 'Invalid 10 user input'),
 11 @ApiResponse(code = 500, response = ErrorResponse, message = 'Unexpected 12 server error')
 13 ])
 14 CustomSettingResponse setSetting(@RequestBody CustomModel settingsValue) {
 15 SaveSettingUpdateRequest request = new SaveSettingUpdateRequest (
 16 settingsValue.fieldOne,
 17 [new TransformedSetting(SettingEnum.POSSIBLE_ENUM_VALUE, 18 new Double(settingsValue.value))]
 19 )
 20 api.saveUpdatedSetting(request)
 21 } Annotation Hell X
  • 53.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 1 @Secured(‘ROLE_ALLOWED_TO_PERFORM_ACTION’)
 2 @RequestMapping(value = '/v1/serviceName/actionName', method = 3 RequestMethod.POST) 4 CustomSettingResponse setSetting(@RequestBody CustomModel settingsValue) {
 5 SaveSettingUpdateRequest request = new SaveSettingUpdateRequest (
 6 settingsValue.fieldOne,
 7 [new TransformedSetting(SettingEnum.POSSIBLE_ENUM_VALUE, 8 new Double(settingsValue.value))]
 9 )
 10 api.saveUpdatedSetting(request)
 11 }
  • 54.
  • 55.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 31
  • 56.
    “Try it” ButtonAlternatives
  • 57.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 33
  • 58.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 34
  • 59.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Curl -> curl 'http://localhost:8080/greetings' -i -H 'Content-Type: text/plain' HTTP/1.1 200 X-Application-Context: application:8080 Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Date:Thu, 26 Jan 2017 13:28:19 GMT [{"id":1,"message":"Hello"},{"id":2,"message":"Hi"},{"id":3,"message":"Hola"},{"id":4,"message":"Olá"},{"id":5,"message":"Hej"}] 35
  • 60.
  • 61.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 37 Swagger2Markup https://github.com/Swagger2Markup/swagger2markup
  • 62.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ img src: http://www.elvenspirit.com/elf/wp-content/uploads/2011/10/IMG_3013.jpg FAIL!
  • 63.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ img src: http://www.elvenspirit.com/elf/wp-content/uploads/2011/10/IMG_3013.jpg FAIL! AssertJ-Swagger https://github.com/RobWin/assertj-swagger
  • 64.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring Cloud Contract 39
  • 65.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 40
  • 66.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 40 Definitions Swagger (OpenAPI Specification) RAML
  • 67.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 40 Definitions Swagger (OpenAPI Specification) RAML Documentation AsciiDoc Markdown Wikis
  • 68.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 40 Definitions Swagger (OpenAPI Specification) RAML Documentation AsciiDoc Markdown Wikis Swagger UI Swagger2Markup
  • 69.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 40 Definitions Swagger (OpenAPI Specification) RAML Testing MockMVC RestAssured Documentation AsciiDoc Markdown Wikis Swagger UI Swagger2Markup
  • 70.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 40 Definitions Swagger (OpenAPI Specification) RAML Testing MockMVC RestAssured Documentation AsciiDoc Markdown Wikis Swagger UI Swagger2Markup AssertJ- Swagger Contract-First
  • 71.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 40 Definitions Swagger (OpenAPI Specification) RAML Testing MockMVC RestAssured Documentation AsciiDoc Markdown Wikis Swagger UI Swagger2Markup Spring REST Docs AssertJ- Swagger Contract-First
  • 72.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs
  • 73.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Development Green Red Refactor
  • 74.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Documentation
  • 75.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Documentation Red
  • 76.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Documentation Red
  • 77.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Documentation Document Red
  • 78.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Documentation Document Red
  • 79.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Documentation Document Green Red
  • 80.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Documentation Document Green Red
  • 81.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Documentation Document Green Red Refactor
  • 82.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Test-Driven Documentation Document Green Red Refactor
  • 83.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Winning Solution https://flic.kr/p/5XiKxU Winning Solution
  • 84.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Winning Solution • Ensures documentation matches implementation • Encourages writing more tests • Reduces duplication in docs and tests • Removes annotations from source X
  • 85.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs 44 https://flic.kr/p/5XiKxU
  • 86.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Game Changers 45 https://flic.kr/p/9Tiv3U
  • 87.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Game Changers •Generated code snippets •Tests fail when documentation is missing or out-of-date •Rest APIs with Hypermedia •Ratpack •Dynamic routing doesn’t work with Swagger X
  • 88.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ About Spring REST Docs 46
  • 89.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ About Spring REST Docs projects.spring.io/spring-restdocs 46
  • 90.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ About Spring REST Docs projects.spring.io/spring-restdocs @springrestdocs 46
  • 91.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ About Spring REST Docs projects.spring.io/spring-restdocs @springrestdocs https://github.com/spring-projects/spring-restdocs 46
  • 92.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ About Spring REST Docs •Start with reading the docs; The written docs are good! •Overview •Sponsored by Pivotal •Project Lead - Andy Wilkinson •Current Version - 2.0.0 released Nov 28 •Twitter Account and Official Logo X
  • 93.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ About Spring REST Docs • Test-Driven Documentation with Spring REST Docs (Java and Spring Boot) - Spring I/O 2016 Andy Wilkinson • Writing comprehensive and guaranteed up-to-date REST API documentation - SpringOne Platform 2016 Anders Evers X
  • 94.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Out of the Box 47
  • 95.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Out of the Box Testing Frameworks • MockMVC • RestAssured • WebTestClient - NEW! 47
  • 96.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Out of the Box Testing Frameworks • MockMVC • RestAssured • WebTestClient - NEW! 47 Build Tools • Gradle • Maven
  • 97.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Out of the Box 48
  • 98.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Out of the Box Documentation Format • AsciiDoc • Markdown 48
  • 99.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Out of the Box Documentation Format • AsciiDoc • Markdown 48 Sample Projects • Spring Boot • Grails • Slate • TestNG • And more!
  • 100.
  • 101.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Groovier Spring REST Docs • Spring Boot • Ratpack • Grails 50
  • 102.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Groovier Spring REST Docs Example - Spring Boot Groovy Spring Boot Project + Asciidoctor Gradle plugin + Spring REST Docs WebTestClient to Spock tests + Add to static assets during build and publish to GitHub pages 51
  • 103.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 52
  • 104.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 52
  • 105.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 52
  • 106.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Groovier Spring REST Docs Example - Spring Boot • Start with lazybones spring boot app • Add mock endpoints for example https://github.com/jlstrater/groovy-spring-boot-restdocs-example Updated to Spring Boot 2.0.0.M7 and thanks to: https://www.callicoder.com/ reactive-rest-apis-spring-webflux-reactive-mongo/ 53
  • 107.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 54
  • 108.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Endpoints @RestController @RequestMapping('/greetings') class GreetingsController { @Autowired GreetingRepository greetingsRepository @PostMapping() Mono<Greeting> createGreeting(@Valid @RequestBody Greeting greeting) { return greetingsRepository.save(greeting) } @GetMapping() Flux<Greeting> listAllGreetings() { return greetingsRepository.findAll() } @GetMapping('/{id}') Mono<Greeting> getGreetingById(@PathVariable(value = 'id') String greetingId) { greetingsRepository.findById(greetingId) } } 55
  • 109.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Endpoints @RestController @RequestMapping('/greetings') class GreetingsController { @Autowired GreetingRepository greetingsRepository @PostMapping() Mono<Greeting> createGreeting(@Valid @RequestBody Greeting greeting) { return greetingsRepository.save(greeting) } @GetMapping() Flux<Greeting> listAllGreetings() { return greetingsRepository.findAll() } @GetMapping('/{id}') Mono<Greeting> getGreetingById(@PathVariable(value = 'id') String greetingId) { greetingsRepository.findById(greetingId) } } 55 Create a new Greeting
  • 110.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Endpoints @RestController @RequestMapping('/greetings') class GreetingsController { @Autowired GreetingRepository greetingsRepository @PostMapping() Mono<Greeting> createGreeting(@Valid @RequestBody Greeting greeting) { return greetingsRepository.save(greeting) } @GetMapping() Flux<Greeting> listAllGreetings() { return greetingsRepository.findAll() } @GetMapping('/{id}') Mono<Greeting> getGreetingById(@PathVariable(value = 'id') String greetingId) { greetingsRepository.findById(greetingId) } } 55 Create a new Greeting List all greetings
  • 111.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Endpoints @RestController @RequestMapping('/greetings') class GreetingsController { @Autowired GreetingRepository greetingsRepository @PostMapping() Mono<Greeting> createGreeting(@Valid @RequestBody Greeting greeting) { return greetingsRepository.save(greeting) } @GetMapping() Flux<Greeting> listAllGreetings() { return greetingsRepository.findAll() } @GetMapping('/{id}') Mono<Greeting> getGreetingById(@PathVariable(value = 'id') String greetingId) { greetingsRepository.findById(greetingId) } } 55 Create a new Greeting List all greetings Get a greeting by id
  • 112.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 56
  • 113.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 56
  • 114.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ AsciiDoc [introduction] = Introduction The Example API is a RESTful web service that shows how Spring REST docs works. [[overview-http-verbs]] == HTTP verbs The Example API tries to adhere as closely as possible to standard HTTP and REST conventions in its use of HTTP verbs. |=== | Verb | Usage | `GET` | Used to retrieve a resource | `POST` | Used to create a new resource | `PUT` | Used to update an existing resource, overwrites all fields 57
  • 115.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Asciidoctor Gradle Plugin 58
  • 116.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ AsciiDoc Gradle Configuration apply plugin: 'org.asciidoctor.convert' asciidoctor { backends 'html5' attributes 'source-highlighter' : 'prettify', 'imagesdir':'images', 'toc':'left', 'icons': 'font', 'setanchors':'true', 'idprefix':'', 'idseparator':'-', 'docinfo1':'true', } 59
  • 117.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 60
  • 118.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 60
  • 119.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
  • 120.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 62
  • 121.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 62
  • 122.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Project Reactor and the WebTestClient 63
  • 123.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Setup @CompileStatic @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class BaseControllerSpec extends Specification { @Autowired ApplicationContext context protected WebTestClient webTestClient void setup() { this.webTestClient = WebTestClient.bindToApplicationContext(this.context) .configureClient() .baseUrl('/greetings') .build() } } 64
  • 124.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Setup @CompileStatic @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class BaseControllerSpec extends Specification { @Autowired ApplicationContext context protected WebTestClient webTestClient void setup() { this.webTestClient = WebTestClient.bindToApplicationContext(this.context) .configureClient() .baseUrl('/greetings') .build() } } 64 If context is null, remember to use spock-spring!!
  • 125.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ WebTestClient Call and Assertions this.webTestClient.post().uri('/') .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .body(BodyInserters.fromObject('{"message": "Hello SpringOne Platform!"}')) .exchange() .expectStatus().isOk() .expectBody() .jsonPath('$.id').isNotEmpty() .jsonPath('$.message').isEqualTo('Hello SpringOne Platform!') 65
  • 126.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 66
  • 127.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 66
  • 128.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs Gradle Configuration dependencies { … testCompile "org.springframework.restdocs:spring-restdocs-webtestclient:${springRestDocsVersion}" asciidoctor "org.springframework.restdocs:spring-restdocs-asciidoctor:${springRestDocsVersion}" } ext { snippetsDir = file('build/generated-snippets') } test { outputs.dir "$projectDir/src/main/resources/public" } asciidoctor { dependsOn test inputs.dir snippetsDir } build { dependsOn asciidoctor } ext['spring-restdocs.version'] = springRestDocsVersion 67
  • 129.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs with WebTestClient (setup) @CompileStatic @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class BaseControllerSpec extends Specification { @Rule JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation() @Autowired ApplicationContext context protected WebTestClient webTestClient void setup() { this.webTestClient = WebTestClient.bindToApplicationContext(this.context) .configureClient() .baseUrl('/greetings') .filter(documentationConfiguration(restDocumentation)) .build() } } 68
  • 130.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs with WebTestClient (setup) @CompileStatic @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class BaseControllerSpec extends Specification { @Rule JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation() @Autowired ApplicationContext context protected WebTestClient webTestClient void setup() { this.webTestClient = WebTestClient.bindToApplicationContext(this.context) .configureClient() .baseUrl('/greetings') .filter(documentationConfiguration(restDocumentation)) .build() } } 68
  • 131.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs with WebTestClient (setup) @CompileStatic @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class BaseControllerSpec extends Specification { @Rule JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation() @Autowired ApplicationContext context protected WebTestClient webTestClient void setup() { this.webTestClient = WebTestClient.bindToApplicationContext(this.context) .configureClient() .baseUrl('/greetings') .filter(documentationConfiguration(restDocumentation)) .build() } } 68
  • 132.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs with WebTestClient (tests) void 'test and document creating a greeting with a custom name'() { expect: this.webTestClient.post().uri('/') .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .body(BodyInserters.fromObject('{"message": "Hello SpringOne Platform!"}')) .exchange() .expectStatus().isOk() .expectBody() .jsonPath('$.id').isNotEmpty() .jsonPath('$.message').isEqualTo('Hello SpringOne Platform!') .consumeWith(document('greetings-post-example', preprocessRequest(prettyPrint()), requestFields( fieldWithPath('message').type(JsonFieldType.STRING) .description("The greeting's message")))) }` 69
  • 133.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs with WebTestClient (tests) void 'test and document creating a greeting with a custom name'() { expect: this.webTestClient.post().uri('/') .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .body(BodyInserters.fromObject('{"message": "Hello SpringOne Platform!"}')) .exchange() .expectStatus().isOk() .expectBody() .jsonPath('$.id').isNotEmpty() .jsonPath('$.message').isEqualTo('Hello SpringOne Platform!') .consumeWith(document('greetings-post-example', preprocessRequest(prettyPrint()), requestFields( fieldWithPath('message').type(JsonFieldType.STRING) .description("The greeting's message")))) }` 69
  • 134.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs with WebTestClient (tests) void 'test and document get of a list of greetings'() { expect: this.webTestClient.get().uri('/').accept(MediaType.APPLICATION_JSON) .exchange() .expectStatus().isOk() .expectBody() .consumeWith(document('greetings-list-example', preprocessResponse(prettyPrint()), responseFields(greetingList))) } FieldDescriptor[] greetingList = new FieldDescriptor().with { [fieldWithPath('[].id').type(JsonFieldType.STRING).optional() .description("The greeting's id"), fieldWithPath('[].message').type(JsonFieldType.STRING) .description("The greeting's message")] } 70
  • 135.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs with WebTestClient (tests) void 'test and document get of a list of greetings'() { expect: this.webTestClient.get().uri('/').accept(MediaType.APPLICATION_JSON) .exchange() .expectStatus().isOk() .expectBody() .consumeWith(document('greetings-list-example', preprocessResponse(prettyPrint()), responseFields(greetingList))) } FieldDescriptor[] greetingList = new FieldDescriptor().with { [fieldWithPath('[].id').type(JsonFieldType.STRING).optional() .description("The greeting's id"), fieldWithPath('[].message').type(JsonFieldType.STRING) .description("The greeting's message")] } 70
  • 136.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring REST Docs with WebTestClient (tests) void 'test and document get of a list of greetings'() { expect: this.webTestClient.get().uri('/').accept(MediaType.APPLICATION_JSON) .exchange() .expectStatus().isOk() .expectBody() .consumeWith(document('greetings-list-example', preprocessResponse(prettyPrint()), responseFields(greetingList))) } FieldDescriptor[] greetingList = new FieldDescriptor().with { [fieldWithPath('[].id').type(JsonFieldType.STRING).optional() .description("The greeting's id"), fieldWithPath('[].message').type(JsonFieldType.STRING) .description("The greeting's message")] } 70
  • 137.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Error Messages 71
  • 138.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Error Messages 71
  • 139.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Error Messages 71
  • 140.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Error Messages 71
  • 141.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Error Messages 71
  • 142.
  • 143.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 
 +@WebMvcTest(controllers = GreetingsController)
 +@AutoConfigureRestDocs(
 + outputDir = "build/generated-snippets",
 + uriHost = “api.example.com”,
 + uriPort = 8080
 ) class BaseControllerSpec extends Specification { 
 // @Rule
 // JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation('src/docs/generated-snippets')
 
 + @Autowired
 protected MockMvc mockMvc
 //
 // @Autowired
 // private WebApplicationContext context
 //
 // void setup() {
 // this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
 // .apply(documentationConfiguration(this.restDocumentation))
 // .build()
 // } } 73
  • 144.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 74
  • 145.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 74
  • 146.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Generated Snippets 75 By Default When Specified curl-request.adoc response-fields.adoc http-request.adoc request-parameters.adoc httpie-request.adoc request-parts.adoc http-response.adoc path-parameters.adoc request body request-parts.adoc response body
  • 147.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ http-request.adoc [source,http,options="nowrap"] ---- POST /greetings/ HTTP/1.1 Content-Type: application/json Accept: application/json Host: localhost:8080 Content-Length: 45 { "message" : "Hello SpringOne Platform!" } ---- 76
  • 148.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ response-fields.adoc |=== |Path|Type|Description |`id` |`String` |The greeting's id |`message` |`String` |The greeting's message |=== 77
  • 149.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 78
  • 150.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 79 +
  • 151.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 79 +
  • 152.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Adding The Snippets [[overview-errors]] == Errors Whenever an error response (status code >= 400) is returned, the body will contain a JSON object that describes the problem. The error object has the following structure: include::{snippets}/error-example/response-fields.adoc[] For example, a request that attempts to delete on the greetings endpoint will produce a `405 Method Not Allowed` response: operation::error-example[snippets='curl-request,http-request,http-response'] [[resources]] = Resources include::resources/greetings.adoc[] 80
  • 153.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Adding The Snippets [[overview-errors]] == Errors Whenever an error response (status code >= 400) is returned, the body will contain a JSON object that describes the problem. The error object has the following structure: include::{snippets}/error-example/response-fields.adoc[] For example, a request that attempts to delete on the greetings endpoint will produce a `405 Method Not Allowed` response: operation::error-example[snippets='curl-request,http-request,http-response'] [[resources]] = Resources include::resources/greetings.adoc[] 80
  • 154.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Adding The Snippets [[overview-errors]] == Errors Whenever an error response (status code >= 400) is returned, the body will contain a JSON object that describes the problem. The error object has the following structure: include::{snippets}/error-example/response-fields.adoc[] For example, a request that attempts to delete on the greetings endpoint will produce a `405 Method Not Allowed` response: operation::error-example[snippets='curl-request,http-request,http-response'] [[resources]] = Resources include::resources/greetings.adoc[] 80
  • 155.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Adding The Snippets [[overview-errors]] == Errors Whenever an error response (status code >= 400) is returned, the body will contain a JSON object that describes the problem. The error object has the following structure: include::{snippets}/error-example/response-fields.adoc[] For example, a request that attempts to delete on the greetings endpoint will produce a `405 Method Not Allowed` response: operation::error-example[snippets='curl-request,http-request,http-response'] [[resources]] = Resources include::resources/greetings.adoc[] 80
  • 156.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 81
  • 157.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 81
  • 158.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Building the docs . 82 src/docs/ asciidoc index.adoc build/asciidoc/ html5 index.html .gradlew asciidoctor
  • 159.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
  • 160.
  • 161.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Publishing Strategies • Hook in asciidoctor with the gradle build task • Run the asciidoctor test separately (but make sure to run AFTER the tests) • Send to static resources directory in the current app or send to a remote site (for example Github Pages X
  • 162.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 85
  • 163.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 85 http://api.example.com/docs
  • 164.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ publish.gradle buildscript { repositories { jcenter() } dependencies { classpath 'org.ajoberstar:gradle-git:1.1.0' } } apply plugin: 'org.ajoberstar.github-pages' githubPages { repoUri = 'git@github.com:jlstrater/groovy-spring-boot-restdocs-example.git' pages { from(file('build/asciidoc/html5')) } } 86
  • 165.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ publish.gradle buildscript { repositories { jcenter() } dependencies { classpath 'org.ajoberstar:gradle-git:1.1.0' } } apply plugin: 'org.ajoberstar.github-pages' githubPages { repoUri = 'git@github.com:jlstrater/groovy-spring-boot-restdocs-example.git' pages { from(file('build/asciidoc/html5')) } } 86 If you use this method, remember to deploy docs at the same time as the project!
  • 166.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 87
  • 167.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 87 http://jlstrater.github.io/groovy- spring-boot-restdocs-example
  • 168.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 87 http://jlstrater.github.io/groovy- spring-boot-restdocs-example ./gradlew publish
  • 169.
  • 170.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Groovier Spring REST Docs • Ratpack • Grails 89
  • 171.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
  • 172.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
  • 173.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
  • 174.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Groovier Spring REST Docs Example - Ratpack • Ratpack Example Project • https://github.com/ratpack/example-books • Spring RESTdocs RestAssured • https://github.com/ratpack/example-books/pull/25 92
  • 175.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Groovier Spring REST Docs Example - Ratpack path(":isbn") {
 def isbn = pathTokens["isbn"]
 
 byMethod {
 get {
 bookService.find(isbn).
 single().
 subscribe { Book book ->
 if (book == null) {
 clientError 404
 } else {
 render book
 }
 }
 } ... }
 } 93 byMethod {
 get {
 bookService.all().
 toList().
 subscribe { List<Book> books ->
 render json(books)
 }
 }
 post {
 parse(jsonNode()).
 observe().
 flatMap { input ->
 bookService.insert(
 input.get("isbn").asText(),
 input.get("quantity").asLong(),
 input.get("price").asDouble()
 )
 }.
 single().
 flatMap {
 bookService.find(it)
 }.
 single().
 subscribe { Book createdBook ->
 render createdBook
 }
 } }
  • 176.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Groovier Spring REST Docs Example - Ratpack path(":isbn") {
 def isbn = pathTokens["isbn"]
 
 byMethod {
 get {
 bookService.find(isbn).
 single().
 subscribe { Book book ->
 if (book == null) {
 clientError 404
 } else {
 render book
 }
 }
 } ... }
 } 93 byMethod {
 get {
 bookService.all().
 toList().
 subscribe { List<Book> books ->
 render json(books)
 }
 }
 post {
 parse(jsonNode()).
 observe().
 flatMap { input ->
 bookService.insert(
 input.get("isbn").asText(),
 input.get("quantity").asLong(),
 input.get("price").asDouble()
 )
 }.
 single().
 flatMap {
 bookService.find(it)
 }.
 single().
 subscribe { Book createdBook ->
 render createdBook
 }
 } } Get a book by ISBN /api/books/1932394842
  • 177.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Groovier Spring REST Docs Example - Ratpack path(":isbn") {
 def isbn = pathTokens["isbn"]
 
 byMethod {
 get {
 bookService.find(isbn).
 single().
 subscribe { Book book ->
 if (book == null) {
 clientError 404
 } else {
 render book
 }
 }
 } ... }
 } 93 byMethod {
 get {
 bookService.all().
 toList().
 subscribe { List<Book> books ->
 render json(books)
 }
 }
 post {
 parse(jsonNode()).
 observe().
 flatMap { input ->
 bookService.insert(
 input.get("isbn").asText(),
 input.get("quantity").asLong(),
 input.get("price").asDouble()
 )
 }.
 single().
 flatMap {
 bookService.find(it)
 }.
 single().
 subscribe { Book createdBook ->
 render createdBook
 }
 } } Get a book by ISBN /api/books/1932394842 Get all books /api/books
  • 178.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Groovier Spring REST Docs Example - Ratpack path(":isbn") {
 def isbn = pathTokens["isbn"]
 
 byMethod {
 get {
 bookService.find(isbn).
 single().
 subscribe { Book book ->
 if (book == null) {
 clientError 404
 } else {
 render book
 }
 }
 } ... }
 } 93 byMethod {
 get {
 bookService.all().
 toList().
 subscribe { List<Book> books ->
 render json(books)
 }
 }
 post {
 parse(jsonNode()).
 observe().
 flatMap { input ->
 bookService.insert(
 input.get("isbn").asText(),
 input.get("quantity").asLong(),
 input.get("price").asDouble()
 )
 }.
 single().
 flatMap {
 bookService.find(it)
 }.
 single().
 subscribe { Book createdBook ->
 render createdBook
 }
 } } Get a book by ISBN /api/books/1932394842 Get all books /api/books Post to create a new book /api/books
  • 179.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 94 https://github.com/jayway/rest-assured
  • 180.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ abstract class BaseDocumentationSpec extends Specification {
 
 @Shared
 ApplicationUnderTest aut = new ExampleBooksApplicationUnderTest()
 
 @Rule
 JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation()
 
 protected RequestSpecification documentationSpec
 
 void setup() {
 this.documentationSpec = new RequestSpecBuilder()
 .addFilter(documentationConfiguration(restDocumentation))
 .build()
 }
 } 95
  • 181.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 96
  • 182.
  • 183.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Blog Post https://jennstrater.blogspot.com/2017/01/using-spring-rest-docs-to-document.html 98
  • 184.
  • 185.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Outcomes • Made it to production! :) • Team was happy with Spring REST Docs • Other dev teams like to see the examples X
  • 186.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Read the Docs for More On… • Adding Security and Headers • Documenting Constraints • Hypermedia Support • XML Support • Using Markdown instead of Asciidoc • Third Party Extensions for WireMock, Jersey, Spring Cloud Contracts, AutoRestDocs 100
  • 187.
  • 188.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 102 Definitions Swagger (OpenAPI Specification) RAML Testing MockMVC RestAssured Documentation AsciiDoc Markdown Wikis Swagger UI Swagger2Markup Spring REST Docs AssertJ- Swagger Contract-First
  • 189.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Conclusion • API documentation is complex • Choosing the right tool for the job not just about the easiest one to setup • Spring REST Docs is a promising tool to enforce good testing and documentation practices without muddying source code. • I still hate writing boilerplate documentation, but at least it’s a little less painful now. X
  • 190.
    Unless otherwise indicated,these slides are © 2013-2016 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Next Steps • Join the Groovy Community on Slack groovycommunity.com • Join #spring-restdocs on gitter https://gitter.im/spring-projects/spring-restdocs 103
  • 191.
    Learn More. StayConnected. https://speakerdeck.com/jlstrater/test-driven-docs-springone-2017 Follow on Twitter @codeJENNerator 104 #springone@s1p