Document it

Hello everyone! In this article, I would like to consider documentation tools in fundamentally different approaches to REST API development, namely, for CodeFirst - SpringRestDocs tools (as well as its SpringAutoRestDocs add-on) and for ApiFirst - Swagger ecosystem tools (Open-Api).





Disclaimer: I will not go into the details of the holivar on what is better than CodeFirst or ApiFirst, but I will try to demonstrate the possible practice of documentation in both versions.





CodeFirst plus SpringAutoRestDocs

SpringRestDocs , (, ..) . , , - , .. SpringAutoRestDocs, JSR Spring , Javadoc, .





SpringAutoRestDocs

SpringAutoRestDocs SpringRestDocs, . - .





:





  • , Jackson, Javadocs





  • JSR-303









.





Swagger PetStore ( , ) (addPet



, deletePet



, getPetById



). getPetById







:





@RestController
@RequiredArgsConstructor
public class PetController implements PetApi {

    private final PetRepository petRepository;
    
    @Override
    public ResponseEntity<Pet> getPetById(Long petId) {
        return new ResponseEntity<>(petRepository.getPetById(petId), HttpStatus.OK);
    }
  //   
}
      
      



.





:





, . , MockMvc



( ):





@Before
void setUp() throws Exception {
  this.mockMvc = MockMvcBuilders
    .webAppContextSetup(context)
    .alwaysDo(prepareJackson(objectMapper, new TypeMapping()))
    .alwaysDo(commonDocumentation())
    .apply(documentationConfiguration(restDocumentation)
           .uris().withScheme("http").withHost("localhost").withPort(8080)
           .and()
           .snippets().withTemplateFormat(TemplateFormats.asciidoctor())
           .withDefaults(curlRequest(), httpRequest(), httpResponse(),
                         requestFields(), responseFields(), pathParameters(),
                         requestParameters(), description(), methodAndPath(),
                         section(), links(), embedded(), authorization(DEFAULT_AUTHORIZATION),
                         modelAttribute(requestMappingHandlerAdapter.getArgumentResolvers())))
    .build()
  }

protected RestDocumentationResultHandler commonDocumentation(Snippet... snippets) {
  return document("rest-auto-documentation/{class-name}/{method-name}", commonResponsePreprocessor(), snippets)
  }

protected OperationResponsePreprocessor commonResponsePreprocessor() {
  return preprocessResponse(replaceBinaryContent(), limitJsonArrayLength(objectMapper), prettyPrint())
  }
      
      



MockMVC

WebApplicationContext



@SpringBootTest







prepareJackson(objectMapper, new TypeMapping())



ResultHandler



, pojo





withDefaults(curlRequest(), httpRequest(), ..)



,





commonDocumentation()



, build , .





:





.





@Test
void getPetTest() {
//given
def petId = 1L
//when
def resultActions = mockMvc
	.perform(RestDocumentationRequestBuilders
		.get("/pet/{petId}", petId)
		.header("Accept", "application/json"))
//then
resultActions
	.andExpect(status().isOk())
	.andExpect(content().string(objectMapper.writeValueAsString(buildReturnPet())))
}
      
      



MockMvc



, .





:





"" auto-section.adoc



( , MockMVC



) index.adoc



API. :





: , html .





SprinAutoRestDocs , . , .





SpringAutoRestDocs SpringRestDocs.





  • - org/springframework/restdocs/templates/asciidoctor default-



    .





  • - org/springframework/restdocs/constraints DefaultConstraintDescriptions.properties



    .





:





ApiFirst Swagger

(1, 2) swagger - open-source , OpenApi Specification , REST api.





Swagger

Swagger - OpenApi Specification Swagger Tools.





  • OpenApi Specification - REST API. YAML JSON. , .





  • Swagger Tools - , - REST api. : Swagger Editor( , ), Swagger UI( API), Swagger Codegen( - , )





- : (swagger-library), swagger-ui(swagger-webjar-ui-starter), (spring-auto-rest-docs).





Swagger Swagger PetStore SpringAutoRestDocs .





build.gradle :





server stub Swagger OpenApi Generator.





OpenApi Generator

gradle gradle plugin OpenApi Generator.





- , . .





:





openApiGenerate {
    generatorName = 'spring'
    inputSpec = specFile
    outputDir = "${project.projectDir}/"
    id = "${artifactId}"
    groupId = projectPackage
    ignoreFileOverride = ignoreFile
    apiPackage = "${projectPackage}.rest.api"
    invokerPackage = "${projectPackage}.rest.invoker"
    modelPackage = "${projectPackage}.rest.model"
    configOptions = [
            dateLibrary            : 'java8',
            hideGenerationTimestamp: 'true',
            interfaceOnly          : 'true',
            delegatePattern        : 'false',
            configPackage          : "${projectPackage}.configuration"
    ]
}
      
      



openApiGenerate
  • generatorName -





  • Spring ( spring)





  • dateLibrary - (joda, JSR-310 ..)





  • ,





:





task codegen(dependsOn: ['openApiGenerate', 'copySpecs'])

compileJava.dependsOn(codegen)
compileJava.mustRunAfter(codegen)
      
      



, UI :





task copySpecs(type: Copy) {
    from("${project.projectDir}/specs")
    into("${project.projectDir}/src/main/resources/META-INF/specs")
}
      
      



Asciidoc Html2.





Swagger-ui :





webjar swagger-ui .





Rest-docs API:





UI :





@RestController
@RestController
@RequiredArgsConstructor
public class PetController implements PetApi {

    private final PetRepository petRepository;
    
    @Override
    public ResponseEntity<Pet> getPetById(Long petId) {
        return new ResponseEntity<>(petRepository.getPetById(petId), HttpStatus.OK);
    }
  //   
}
      
      



swagger:
  ui:
    indexHandler:
      enabled: true
      resourceHandler: "/api/**"
    apis:
      - url: http://localhost:8080/specs/some_swagger.yaml
        name: My api
      
      



:





Server stub - API.





Swagger UI - API UI:





Asciidoc Html2 swagger :





:

SpringAutoRestDocs:





  • ( index.html ), .





  • , "" .





  • The ability to customize snippets and restrictions.





What Swagger gives:





  • A single artifact at all stages of development.





  • The documentation and data model is always in sync with the code, as the code is generated based on a contract.





  • The ability to use a UI that contains all the same information as in the contract with the ability to route requests.





Whichever development path you choose, the tools above will almost always allow you to keep up-to-date documentation closely related to the production code.








All Articles