Jan Mewes
Posted on May 13, 2023
Motivation
Creating the OpenAPI specification (OAS) before the implementation of the API might lead to a better API design than the generation of the OAS from the implementation, the generations of the OAS from the tests, or not using OAS altogether.
However, this raises the need to validate that the implementation complies with the OAS. This may be done with Atlassian's open-source project swagger-request-validator as described below.
Also see
- Using spec-first API development for speed and sanity | atlassian.com
- Episode 542: Brendan Callum on Contract-Driven APIs | se-radio.net
Overview
swagger-request-validator has a core component and allows integration with different testing approaches with a handful of sub-components. One of those sub-components is swagger-request-validator-mockmvc which integrates with Spring Mock MVC coming from spring-test that it used in the tests of the ksch.patientmanagment.impl project.
swagger-request-validator-core leverages jackson, io.swagger.core and io.swagger.parser to parse the test data and OAS. Then it matches them with the help of java-json-tools and reports violations if they don't match.
Those dependencies are visualized in the following UML Component diagram:
Implementation details
The swagger-request-validator library can be included by declaring the following dependencies in the build.gradle
file:
dependencies {
testImplementation('com.atlassian.oai:swagger-request-validator-core:2.34.1')
testImplementation('com.atlassian.oai:swagger-request-validator-mockmvc:2.34.1')
}
To allow the usage of the allOf
feature of OAS, the withResolveCombinators
option of OpenApiInteractionValidator
needs to be set to true
(see swagger-request-validator#315) and additional properties need to be ignored.
public static OpenApiInteractionValidator createValidator(String specificationUrl) {
LevelResolver levelResolver = LevelResolver.create()
.withLevel("validation.schema.additionalProperties", ValidationReport.Level.IGNORE)
.build();
ParseOptions parseOptions = new ParseOptions();
parseOptions.setResolve(true);
parseOptions.setResolveFully(false);
parseOptions.setResolveCombinators(true);
return OpenApiInteractionValidator
.createForSpecificationUrl(specificationUrl)
.withLevelResolver(levelResolver)
.withParseOptions(parseOptions)
.build();
}
Then the openApi()
validation can be added to the MockMVC expectations in the test.
OpenApiInteractionValidator validator = OasValidatorFactory.createValidator(
"../../docs/openapi.yml"
);
mockMvc.perform(post("/api/patients").accept(APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("_id", is(notNullValue())))
.andExpect(openApi().isValid(validator))
;
References
Posted on May 13, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
August 31, 2024