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, .
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);
}
//
}
.
:
@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. :
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
:
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")
}
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:
:
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.