introducing spring auto rest docs - spring io 2017

Post on 28-Jan-2018

808 Views

Category:

Software

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

IntroducingSpring Auto REST Docs

Florian Benz@flbenz

@spring_io#springio17

DR REST DOCS

OR: HOW I LEARNED TO STOP WORRYING AND LOVE DOCUMENTATION

@spring_io#springio17

Florian Benz

Software Engineer

@flbenz

@spring_io#springio17

Scalable Capital

• Europe’s fastest growing Digital Wealth Manager

• Authorized financial institute in Germany and the UK

• From scratch with Spring Boot

• Joined effort with Juraj Misur @juraj_misur

@spring_io#springio17

Spring Auto REST Docs

Scalable Capital founded

Dec 2014

Proof of concept

Jul 2015

First article

Nov 2015

@spring_io#springio17

Spring Auto REST Docs

Open source&

First release

Dec 2016

DZone article

Jan 2017

Two releases with fixes and

features

Feb & Mar 2017

@spring_io#springio17

Our Story

@spring_io#springio17

Manual Documentation

DocumentationCode

@spring_io#springio17

A single big document

@spring_io#springio17

Specification-Driven Documentation

DocumentationCode

Specification

@spring_io#springio17

RAML Specification/weather:

get:

queryParameters:

city:

description: Name of a city in the given country.

responses:

200:

body:

application/json:

schema: |

{ "$schema": "http://json-schema.org/schema",

"type": "object",

"description": "Weather information",

"properties": {

"temperature": { "type": "number" }

}

}

@spring_io#springio17

Swagger / OpenAPI@GetMapping("weatherParam")@ApiOperation("weather")@ApiImplicitParams({ @ApiImplicitParam(name = "country", value = "Country code", required = true, dataType = "string", paramType = "query"), @ApiImplicitParam(name = "city", value = "City", required = true, dataType = "string", paramType = "query")})@ApiResponses({ @ApiResponse(code = 200, message = "Success", response = WeatherResponse.class)})public WeatherResponse weatherParam(@RequestParam @IsoCountryCode String country, @RequestParam String city) { return new WeatherResponse(20);}

@spring_io#springio17

Swagger / OpenAPI

@spring_io#springio17

Postman

@spring_io#springio17

Test-Driven Documentation

DocumentationCode

Tests

@spring_io#springio17

Spring REST Docs

Generatedsnippets

Tests

Hand-written documentation

Documentation

@spring_io#springio17

Spring MVC Test@Testpublic void shouldReturnWeatherForBarcelona() throws Exception { mockMvc.perform( post("/weather") .contentType(MediaType.APPLICATION_JSON) .content("{\"country\": \"ES\", \"city\": \"Barcelona\"}") ) .andExpect(status().isOk()) .andExpect(jsonPath("$.temperature", is(20)));}

@spring_io#springio17

Spring REST Docs@Testpublic void shouldReturnWeatherForBarcelona() throws Exception { mockMvc.perform( post("/weather") .contentType(MediaType.APPLICATION_JSON) .content("{\"country\": \"ES\", \"city\": \"Barcelona\"}") ) .andExpect(status().isOk()) .andExpect(jsonPath("$.temperature", is(20))); .andDo(document("weather", requestFields( fieldWithPath("country").description("Country code"), fieldWithPath("city").description("City name"))));}

@spring_io#springio17

Generated snippet|===|Path|Type|Optional|Description

|country|String|false|Country Code.

|city|false|true|City name.

|===

@spring_io#springio17

AsciiDoc[[resources-weather]]= Weather for your city

`POST /weather`

Up-to-date temperature for the given city

== Response structure

include::{snippets}/weather/response-fields.adoc[]

== Example request/response

include::{snippets}/weather/curl-request.adoc[]include::{snippets}/weather/http-response.adoc[]

@spring_io#springio17

Spring REST Docs

@spring_io#springio17

Spring REST Docs

@spring_io#springio17

Spring REST Docs

Controller

POJO

Response Entity

Jackson

HTTP response Documented

@spring_io#springio17

ExtendingSpring REST Docs

@spring_io#springio17

Motivation

.andDo(document("weather", requestFields( fieldWithPath("country").description("Country code"), fieldWithPath("city").description("Name of a city"))));

We are lazy

@spring_io#springio17

Proof of concept

@spring_io#springio17

Spring Auto REST Docs

Controller

POJO

Response Entity

Jackson

HTTP response

Javadoc

Introspection

@spring_io#springio17

Spring REST Docs@Testpublic void shouldReturnWeatherForBarcelona() throws Exception { mockMvc.perform( post("/weather") .contentType(MediaType.APPLICATION_JSON) .content("{\"country\": \"ES\", \"city\": \"Barcelona\"}") ) .andExpect(status().isOk()) .andExpect(jsonPath("$.temperature", is(20))); .andDo(document("weather", requestFields( fieldWithPath("country").optional().description("Country code"), fieldWithPath("city").optional().description("City name"))));}

@spring_io#springio17

Spring Auto REST Docs@Testpublic void shouldReturnWeatherForBarcelona() throws Exception { mockMvc.perform( post("/weather") .contentType(MediaType.APPLICATION_JSON) .content("{\"country\": \"ES\", \"city\": \"Barcelona\"}") ) .andExpect(status().isOk()) .andExpect(jsonPath("$.temperature", is(20))); .andDo(document("weather"));}

@spring_io#springio17

Javadocclass WeatherRequest { /** * Country code. */ private String country; /** * City name. */ private String city;}

Path Type Optional Description

country String true Country code.

city String true City name.

@spring_io#springio17

Constraintsclass WeatherRequest { /** * Country code, e.g. ES, DE, US. */ @NotNull @IsoCountryCode private String country; /** * City name. */ @NotBlank private String city;}

Path Type Optional Description

country String false Country code.Must be an ISO country code.

city String false City name.

@spring_io#springio17

Constraints

package.OneOf.description=Must be one of ${value}package.IsoCountryCode.description=Must be an ISO country code

ConstraintDesciptions.properties

@spring_io#springio17

Constraintsclass WeatherRequest { /** * Country code, e.g. ES, DE, US. */ @NotNull @IsoCountryCode(groups = Iso.class) @CountryName(groups = Plain.class) private String country;}

Path Type Optional Description

country String false Country code.ISO: Must be an ISO country code.Plain: Must be a country name.

@spring_io#springio17

Enumsclass WeatherRequest { /** * Country code, e.g. ES, DE, US. */ @NotNull private Country country; /** * City name. */ @NotBlank private String city;}

Path Type Optional Description

country String false Country code.Must be one of [DE, ES, FR, PT, US].

city String false City name.

@spring_io#springio17

Original: hand-written

2.8. WeatherPOST /weather

Up-to-date weather data for cities around the globe.

[[resources-weather]]= Weather for your city

`POST /weather`

Up-to-date temperature for the given city

@spring_io#springio17

Extension: Javadoc on method/*** Up-to-date weather data for cities around the globe.*/@PostMapping("weather")public WeatherResponse weather( @RequestBody @Valid WeatherRequest weatherRequest) { return new WeatherResponse(20);}

2.8. WeatherPOST /weather

Up-to-date weather data for cities around the globe.

@spring_io#springio17

Original: Path Parameters

.andDo(document("weather", pathParameters( parameterWithName("country").description("Country code"), parameterWithName("city").description("City name"))));

@spring_io#springio17

Extension: Path Parameters/*** Up-to-date weather data for cities around the globe.** @param country Country code.* @param city City name.*/@GetMapping("weather/{country}/{city}")public WeatherResponse weatherPath( @PathVariable @IsoCountryCode String country, @PathVariable String city) { return new WeatherResponse(20);}

@spring_io#springio17

Path Parameters

@spring_io#springio17

Path Parameters

@spring_io#springio17

Original: Query Parameters

.andDo(document("weather", requestParameters( parameterWithName("country").description("Country code"), parameterWithName("city").description("City name"))));

@spring_io#springio17

Extension: Query Parameters/** * Up-to-date weather data for cities around the globe.** @param country Country code.* @param city City name.*/@GetMapping("weatherParam")public WeatherResponse weatherParam( @RequestParam @IsoCountryCode String country, @RequestParam String city) { return new WeatherResponse(20);}

@spring_io#springio17

Query Parameters

@spring_io#springio17

Query Parameters

@spring_io#springio17

Section Snippet[[resources-weather]]=== Weather for your city

`POST /weather`

Up-to-date temperature for the given city

===== Request structure

include::{snippets}/weather/request-fields.adoc[]

===== Response structure

include::{snippets}/weather/response-fields.adoc[]

===== Example request/response

include::{snippets}/weather/curl-request.adoc[]include::{snippets}/weather/http-response.adoc[]

include::{snippets}/weather/section.adoc[]

Documentation path

Spring MVC Controller

Javadoc

Method name

@spring_io#springio17

Authorization snippet

@spring_io#springio17

Content Modifiers

[ 1, 2, 3, 4, 5]

[ 1, 2, 3]

array shortener

@spring_io#springio17

Content Modifiers

%PDF-1.5%����12 0 obj<</Length 3654 /Filter /FlateDecode>>

<binary>

binary replacement

@spring_io#springio17

Benefits

Less to write

Code review Maintainability

Happier developers

DRY

Accurate

@spring_io#springio17

Sounds good!

Issues?

@spring_io#springio17

Issues

@spring_io#springio17

Issues

@spring_io#springio17

Issues

@spring_io#springio17

It’s an extension

Authorization snippet

Javadoc/introspection snippets

Content modifiers

@spring_io#springio17

Spring Auto REST Docsat Scalable Capital

@spring_io#springio17

Spring Auto REST Docsat Scalable Capital

@spring_io#springio17

Thank you

@spring_io#springio17

Q&A

@flbenz

top related