Documentez-le

Bonjour à tous! Dans cet article, j'aimerais examiner les outils de documentation dans des approches fondamentalement différentes du développement d'API REST, à savoir, pour les outils CodeFirst - SpringRestDocs (ainsi que son module complémentaire SpringAutoRestDocs) et pour les outils de l'écosystème ApiFirst - Swagger (Open-Api).





Avertissement: Je n'entrerai pas dans les détails de l'holivar sur ce qui est mieux que CodeFirst ou ApiFirst, mais je vais essayer de démontrer la pratique possible de la documentation dans les deux versions.





CodeFirst et 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 ), .





  • , "" .





  • La possibilité de personnaliser les extraits et les restrictions.





Ce que Swagger donne:





  • Un seul artefact à tous les stades de développement.





  • La documentation et le modèle de données sont toujours synchronisés avec le code, car le code est généré sur la base d'un contrat.





  • La possibilité d'utiliser une interface utilisateur contenant toutes les mêmes informations que dans le contrat avec la possibilité d'acheminer les demandes.





Quel que soit le chemin de développement que vous choisissez, les outils ci-dessus vous permettront presque toujours de garder une documentation à jour étroitement liée au code de production.








All Articles