Dokumentieren Sie es

Hallo zusammen! In diesem Artikel möchte ich Dokumentationstools in grundlegend unterschiedlichen Ansätzen für die REST-API-Entwicklung betrachten, nämlich für CodeFirst - SpringRestDocs-Tools (sowie das SpringAutoRestDocs-Add-On) und für ApiFirst - Swagger-Ökosystem-Tools (Open-Api).





Haftungsausschluss: Ich werde nicht auf die Details des Holivars eingehen, was besser ist als CodeFirst oder ApiFirst, aber ich werde versuchen, die mögliche Praxis der Dokumentation in beiden Versionen zu demonstrieren.





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





  • , "" .





  • Die Möglichkeit, Snippets und Einschränkungen anzupassen.





Was Swagger gibt:





  • Ein einziges Artefakt in allen Entwicklungsstadien.





  • Das Dokumentations- und Datenmodell ist immer mit dem Code synchron, da der Code auf der Grundlage eines Vertrags generiert wird.





  • Die Möglichkeit, eine Benutzeroberfläche zu verwenden, die dieselben Informationen wie im Vertrag enthält, mit der Möglichkeit, Anforderungen weiterzuleiten.





Unabhängig davon, welchen Entwicklungspfad Sie wählen, können Sie mit den oben genannten Tools fast immer eine aktuelle Dokumentation führen, die eng mit dem Produktionscode zusammenhängt.








All Articles