SlideShare a Scribd company logo
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

More Related Content

PPTX
DevOps and Continuous Delivery Reference Architectures - Volume 2
PDF
Spring Tools 4 - Eclipse and Beyond
PPTX
DevOps Architecture Design
PDF
OpenAPI 3.0, And What It Means for the Future of Swagger
PDF
Continuous Delivery: Fly the Friendly CI in Pivotal Cloud Foundry with Concourse
PDF
Enterprise CI as-a-Service using Jenkins
PDF
Working effectively with OpenShift
PDF
Developing Great Apps with Apache Cordova
DevOps and Continuous Delivery Reference Architectures - Volume 2
Spring Tools 4 - Eclipse and Beyond
DevOps Architecture Design
OpenAPI 3.0, And What It Means for the Future of Swagger
Continuous Delivery: Fly the Friendly CI in Pivotal Cloud Foundry with Concourse
Enterprise CI as-a-Service using Jenkins
Working effectively with OpenShift
Developing Great Apps with Apache Cordova

What's hot (20)

PDF
Git Merge and Rebase | Git Merge vs Rebase | Which One to Choose? | Devops Tr...
PDF
MicroProfile: Optimizing Java EE for a Microservices Architecture
PDF
The API Lifecycle Series: Exploring Design-First and Code-First Approaches to...
PDF
MicroProfile Devoxx.us
PDF
Testing strategies and best practices using MUnit
PPTX
Nexus Pro Customer Survey Findings
PPTX
MuleSoft CloudHub API Versioning
PDF
The API Lifecycle Series: Evolving API Development and Testing from Open Sour...
PPTX
Introducing DevOps
PPTX
CICD Pipeline - AWS Azure
PPTX
OpenAPI v.Next - Events, Alternative Schemas & the Road Ahead
PPTX
Enabing DevOps in an SDN World
PDF
Docker introduction
PPT
How to Build a DevOps Toolchain
PPTX
Java cloud service 발표자료
PPTX
Devops and git basics
PPTX
不只自動化而且更敏捷的Android開發工具 gradle
PDF
Laravel CI / CD in Azure Web Apps - Global Azure Bootcamp Jakarta
PPTX
From Continuous Integration to DevOps
PPTX
Leveling Up Deployment Infrastructure
Git Merge and Rebase | Git Merge vs Rebase | Which One to Choose? | Devops Tr...
MicroProfile: Optimizing Java EE for a Microservices Architecture
The API Lifecycle Series: Exploring Design-First and Code-First Approaches to...
MicroProfile Devoxx.us
Testing strategies and best practices using MUnit
Nexus Pro Customer Survey Findings
MuleSoft CloudHub API Versioning
The API Lifecycle Series: Evolving API Development and Testing from Open Sour...
Introducing DevOps
CICD Pipeline - AWS Azure
OpenAPI v.Next - Events, Alternative Schemas & the Road Ahead
Enabing DevOps in an SDN World
Docker introduction
How to Build a DevOps Toolchain
Java cloud service 발표자료
Devops and git basics
不只自動化而且更敏捷的Android開發工具 gradle
Laravel CI / CD in Azure Web Apps - Global Azure Bootcamp Jakarta
From Continuous Integration to DevOps
Leveling Up Deployment Infrastructure
Ad

Similar to Documenting RESTful APIs with Spring REST Docs (20)

PPTX
API Documentation -- Presentation to East Bay STC Chapter
PPTX
API Documentation presentation to East Bay STC Chapter
PPTX
API workshop: Introduction to APIs (TC Camp)
PDF
PDF
Boost Your Content Strategy for REST APIs
PDF
REST API Doc Best Practices
PPTX
API Documentation Workshop tcworld India 2015
PDF
Test-Driven Documentation for your REST(ful) service
PPTX
Super simple introduction to REST-APIs (2nd version)
PDF
Generating docs from APIs
PDF
API Best Practices
PDF
APIDays 2018 - API Development Lifecycle - The secret ingredient behind RESTf...
PDF
O reilly sacon2018nyc - restful api design - master - v1.0
PPTX
Survival Strategies for API Documentation: Presentation to Southwestern Ontar...
PPTX
Documenting an API for the First Time? Quick-Start Tips for Your First API Do...
PPTX
API Athens Meetup - API standards 25-6-2014
PPTX
API Athens Meetup - API standards 25-6-2014
PDF
O'Reilly SACon San Jose, CA - 2019 - API design tutorial
PPTX
Empathic API-Design
PDF
API Docs Made Right / RAML - Swagger rant
API Documentation -- Presentation to East Bay STC Chapter
API Documentation presentation to East Bay STC Chapter
API workshop: Introduction to APIs (TC Camp)
Boost Your Content Strategy for REST APIs
REST API Doc Best Practices
API Documentation Workshop tcworld India 2015
Test-Driven Documentation for your REST(ful) service
Super simple introduction to REST-APIs (2nd version)
Generating docs from APIs
API Best Practices
APIDays 2018 - API Development Lifecycle - The secret ingredient behind RESTf...
O reilly sacon2018nyc - restful api design - master - v1.0
Survival Strategies for API Documentation: Presentation to Southwestern Ontar...
Documenting an API for the First Time? Quick-Start Tips for Your First API Do...
API Athens Meetup - API standards 25-6-2014
API Athens Meetup - API standards 25-6-2014
O'Reilly SACon San Jose, CA - 2019 - API design tutorial
Empathic API-Design
API Docs Made Right / RAML - Swagger rant
Ad

More from VMware Tanzu (20)

PDF
Spring into AI presented by Dan Vega 5/14
PDF
What AI Means For Your Product Strategy And What To Do About It
PDF
Make the Right Thing the Obvious Thing at Cardinal Health 2023
PPTX
Enhancing DevEx and Simplifying Operations at Scale
PDF
Spring Update | July 2023
PPTX
Platforms, Platform Engineering, & Platform as a Product
PPTX
Building Cloud Ready Apps
PDF
Spring Boot 3 And Beyond
PDF
Spring Cloud Gateway - SpringOne Tour 2023 Charles Schwab.pdf
PDF
Simplify and Scale Enterprise Apps in the Cloud | Boston 2023
PDF
Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023
PPTX
tanzu_developer_connect.pptx
PDF
Tanzu Virtual Developer Connect Workshop - French
PDF
Tanzu Developer Connect Workshop - English
PDF
Virtual Developer Connect Workshop - English
PDF
Tanzu Developer Connect - French
PDF
Simplify and Scale Enterprise Apps in the Cloud | Dallas 2023
PDF
SpringOne Tour: Deliver 15-Factor Applications on Kubernetes with Spring Boot
PDF
SpringOne Tour: The Influential Software Engineer
PDF
SpringOne Tour: Domain-Driven Design: Theory vs Practice
Spring into AI presented by Dan Vega 5/14
What AI Means For Your Product Strategy And What To Do About It
Make the Right Thing the Obvious Thing at Cardinal Health 2023
Enhancing DevEx and Simplifying Operations at Scale
Spring Update | July 2023
Platforms, Platform Engineering, & Platform as a Product
Building Cloud Ready Apps
Spring Boot 3 And Beyond
Spring Cloud Gateway - SpringOne Tour 2023 Charles Schwab.pdf
Simplify and Scale Enterprise Apps in the Cloud | Boston 2023
Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023
tanzu_developer_connect.pptx
Tanzu Virtual Developer Connect Workshop - French
Tanzu Developer Connect Workshop - English
Virtual Developer Connect Workshop - English
Tanzu Developer Connect - French
Simplify and Scale Enterprise Apps in the Cloud | Dallas 2023
SpringOne Tour: Deliver 15-Factor Applications on Kubernetes with Spring Boot
SpringOne Tour: The Influential Software Engineer
SpringOne Tour: Domain-Driven Design: Theory vs Practice

Recently uploaded (20)

PPTX
Cloud computing and distributed systems.
PDF
Spectral efficient network and resource selection model in 5G networks
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
madgavkar20181017ppt McKinsey Presentation.pdf
PDF
Sensors and Actuators in IoT Systems using pdf
PDF
solutions_manual_-_materials___processing_in_manufacturing__demargo_.pdf
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
Advanced Soft Computing BINUS July 2025.pdf
PDF
Advanced IT Governance
PDF
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Empathic Computing: Creating Shared Understanding
PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
Cloud computing and distributed systems.
Spectral efficient network and resource selection model in 5G networks
The AUB Centre for AI in Media Proposal.docx
madgavkar20181017ppt McKinsey Presentation.pdf
Sensors and Actuators in IoT Systems using pdf
solutions_manual_-_materials___processing_in_manufacturing__demargo_.pdf
The Rise and Fall of 3GPP – Time for a Sabbatical?
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
20250228 LYD VKU AI Blended-Learning.pptx
Diabetes mellitus diagnosis method based random forest with bat algorithm
Advanced Soft Computing BINUS July 2025.pdf
Advanced IT Governance
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
Network Security Unit 5.pdf for BCA BBA.
Empathic Computing: Creating Shared Understanding
CIFDAQ's Market Insight: SEC Turns Pro Crypto
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Review of recent advances in non-invasive hemoglobin estimation
NewMind AI Weekly Chronicles - August'25 Week I
Advanced methodologies resolving dimensionality complications for autism neur...

Documenting RESTful APIs with Spring REST Docs

  • 1. Documenting RESTful APIs with 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
  • 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!*
  • 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
  • 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
  • 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
  • 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 }
  • 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” Button Alternatives
  • 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
  • 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!
  • 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
  • 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/
  • 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 = '[email protected]: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 = '[email protected]: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
  • 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
  • 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
  • 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
  • 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. Stay Connected. https://speakerdeck.com/jlstrater/test-driven-docs-springone-2017 Follow on Twitter @codeJENNerator 104 #springone@s1p