Skip to content

Commit

Permalink
refs #4455 - add config properties for default response status code
Browse files Browse the repository at this point in the history
  • Loading branch information
frantuma committed Sep 26, 2023
1 parent 9048843 commit fab5000
Show file tree
Hide file tree
Showing 15 changed files with 145 additions and 16 deletions.
3 changes: 2 additions & 1 deletion modules/swagger-gradle-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ Parameter | Description | Required | Default
`modelConverterClasses`|see [configuration property](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false|
`contextId`|see [Context](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#context)|false|
`outputPath`|**DEPRECATED** output path where file(s) are saved|false|

`defaultResponseCode`|see [configuration property](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false|

**Note** parameter `openApiFile` corresponds to [config](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties) openAPI. It points to a location of a file in YAML or JSON format representing the input spec that will be merged with the resolved spec. Typically used to add Info section, or any other meta data.
An example of such file:
Expand All @@ -122,3 +122,4 @@ Since version 2.1.6, `sortOutput` parameter is available, allowing to sort objec
Since version 2.1.6, `objectMapperProcessorClass` allows to configure also the ObjectMapper instance used to serialize the resolved OpenAPI
Since version 2.1.9, `alwaysResolveAppPath` parameter is available, allowing to trigger resolving of Application Path from annotation also not in runtime (e.g. using servlet in separate application, or in maven plugin at build time, etc)
Since version 2.1.15, `skipResolveAppPath` parameter is available, allowing to skip resolving of Application Path from annotation
Since version 2.2.17, `defaultResponseCode` parameter is available, allowing to set the code used when resolving responses with no http status code annotation
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ public enum Format {JSON, YAML, JSONANDYAML};

private Boolean convertToOpenAPI31 = false;

private String defaultResponseCode;

@Input
@Optional
public String getOutputFileName() {
Expand Down Expand Up @@ -227,6 +229,22 @@ public void setObjectMapperProcessorClass(String objectMapperProcessorClass) {
this.objectMapperProcessorClass = objectMapperProcessorClass;
}

/**
* @since 2.2.17
*/
@Input
@Optional
public String getDefaultResponseCode() {
return defaultResponseCode;
}

/**
* @since 2.2.17
*/
public void setDefaultResponseCode(String defaultResponseCode) {
this.defaultResponseCode = defaultResponseCode;
}

/**
* @since 2.0.6
*/
Expand Down Expand Up @@ -461,6 +479,11 @@ public void resolve() throws GradleException {
method.invoke(swaggerLoader, objectMapperProcessorClass);
}

if (StringUtils.isNotBlank(defaultResponseCode)) {
method=swaggerLoaderClass.getDeclaredMethod("setDefaultResponseCode",String.class);
method.invoke(swaggerLoader, defaultResponseCode);
}

method=swaggerLoaderClass.getDeclaredMethod("setPrettyPrint", Boolean.class);
method.invoke(swaggerLoader, prettyPrint);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,9 @@ private OpenAPIConfiguration mergeParentConfiguration(OpenAPIConfiguration confi
if (merged.isConvertToOpenAPI31() == null) {
merged.setConvertToOpenAPI31(parentConfig.isConvertToOpenAPI31());
}
if (merged.getDefaultResponseCode() == null) {
merged.setDefaultResponseCode(parentConfig.getDefaultResponseCode());
}

return merged;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,22 @@ public class SwaggerConfiguration implements OpenAPIConfiguration {

private Boolean convertToOpenAPI31;

@Override
public String getDefaultResponseCode() {
return defaultResponseCode;
}

public void setDefaultResponseCode(String defaultResponseCode) {
this.defaultResponseCode = defaultResponseCode;
}

public SwaggerConfiguration defaultResponseCode(String defaultResponseCode) {
this.defaultResponseCode = defaultResponseCode;
return this;
}

private String defaultResponseCode;

public Long getCacheTTL() {
return cacheTTL;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,9 @@ public interface OpenAPIConfiguration {
* @since 2.2.12
*/
Boolean isConvertToOpenAPI31();

/**
* @since 2.2.17
*/
public String getDefaultResponseCode();
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ public static Optional<RequestBody> getRequestBody(io.swagger.v3.oas.annotations
}

public static Optional<ApiResponses> getApiResponses(final io.swagger.v3.oas.annotations.responses.ApiResponse[] responses, Produces classProduces, Produces methodProduces, Components components, JsonView jsonViewAnnotation) {
return getApiResponses(responses, classProduces, methodProduces, components, jsonViewAnnotation, false);
return getApiResponses(responses, classProduces, methodProduces, components, jsonViewAnnotation, false, ApiResponses.DEFAULT);
}

public static Optional<ApiResponses> getApiResponses(final io.swagger.v3.oas.annotations.responses.ApiResponse[] responses, Produces classProduces, Produces methodProduces, Components components, JsonView jsonViewAnnotation, boolean openapi31) {
public static Optional<ApiResponses> getApiResponses(final io.swagger.v3.oas.annotations.responses.ApiResponse[] responses, Produces classProduces, Produces methodProduces, Components components, JsonView jsonViewAnnotation, boolean openapi31, String defaultResponseKey) {
if (responses == null) {
return Optional.empty();
}
Expand Down Expand Up @@ -103,7 +103,7 @@ public static Optional<ApiResponses> getApiResponses(final io.swagger.v3.oas.ann
if (StringUtils.isNotBlank(response.responseCode())) {
apiResponsesObject.addApiResponse(response.responseCode(), apiResponseObject);
} else {
apiResponsesObject._default(apiResponseObject);
apiResponsesObject.addApiResponse(defaultResponseKey, apiResponseObject);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ public class Reader implements OpenApiReader {
private Paths paths;
private Set<Tag> openApiTags;

private String defaultResponseKey = ApiResponses.DEFAULT;

private static final String GET_METHOD = "get";
private static final String POST_METHOD = "post";
private static final String PUT_METHOD = "put";
Expand Down Expand Up @@ -216,6 +218,7 @@ public void setConfiguration(OpenAPIConfiguration openApiConfiguration) {
this.components = this.openAPI.getComponents();
}
}
this.defaultResponseKey = StringUtils.isBlank(config.getDefaultResponseCode()) ? ApiResponses.DEFAULT : config.getDefaultResponseCode();
}
}

Expand Down Expand Up @@ -1083,7 +1086,9 @@ protected Operation parseMethod(
classProduces,
methodProduces,
components,
jsonViewAnnotation
jsonViewAnnotation,
config.isOpenAPI31(),
defaultResponseKey
).ifPresent(responses -> {
if (operation.getResponses() == null) {
operation.setResponses(responses);
Expand All @@ -1104,7 +1109,9 @@ protected Operation parseMethod(
classProduces,
methodProduces,
components,
jsonViewAnnotation
jsonViewAnnotation,
config.isOpenAPI31(),
defaultResponseKey
).ifPresent(responses -> {
if (operation.getResponses() == null) {
operation.setResponses(responses);
Expand Down Expand Up @@ -1164,20 +1171,20 @@ protected Operation parseMethod(
methodProduces == null ? new String[0] : methodProduces.value(), content, mediaType);
if (operation.getResponses() == null) {
operation.responses(
new ApiResponses()._default(
new ApiResponses().addApiResponse(defaultResponseKey,
new ApiResponse().description(DEFAULT_DESCRIPTION)
.content(content)
)
);
}
if (operation.getResponses().getDefault() != null &&
StringUtils.isBlank(operation.getResponses().getDefault().get$ref())) {
if (operation.getResponses().getDefault().getContent() == null) {
operation.getResponses().getDefault().content(content);
if (operation.getResponses().get(defaultResponseKey) != null &&
StringUtils.isBlank(operation.getResponses().get(defaultResponseKey).get$ref())) {
if (operation.getResponses().get(defaultResponseKey).getContent() == null) {
operation.getResponses().get(defaultResponseKey).content(content);
} else {
for (String key : operation.getResponses().getDefault().getContent().keySet()) {
if (operation.getResponses().getDefault().getContent().get(key).getSchema() == null) {
operation.getResponses().getDefault().getContent().get(key).setSchema(returnTypeSchema);
for (String key : operation.getResponses().get(defaultResponseKey).getContent().keySet()) {
if (operation.getResponses().get(defaultResponseKey).getContent().get(key).getSchema() == null) {
operation.getResponses().get(defaultResponseKey).getContent().get(key).setSchema(returnTypeSchema);
}
}
}
Expand Down Expand Up @@ -1414,7 +1421,7 @@ protected void setOperationObjectFromApiOperationAnnotation(
AnnotationsUtils.getExternalDocumentation(apiOperation.externalDocs(), openapi31).ifPresent(operation::setExternalDocs);
}

OperationParser.getApiResponses(apiOperation.responses(), classProduces, methodProduces, components, jsonViewAnnotation, openapi31).ifPresent(responses -> {
OperationParser.getApiResponses(apiOperation.responses(), classProduces, methodProduces, components, jsonViewAnnotation, openapi31, defaultResponseKey).ifPresent(responses -> {
if (operation.getResponses() == null) {
operation.setResponses(responses);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ public class ServletConfigContextUtils {
*/
public static final String OPENAPI_CONFIGURATION_OBJECT_MAPPER_PROCESSOR_KEY = "openApi.configuration.objectMapperProcessorClass";

/**
* @since 2.2.17
*/
public static final String OPENAPI_CONFIGURATION_DEFAULT_RESPONSE_CODE_KEY = "openApi.configuration.defaultResponseCode";

/**
* @since 2.0.6
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import static io.swagger.v3.jaxrs2.integration.ServletConfigContextUtils.OPENAPI_CONFIGURATION_CACHE_TTL_KEY;
import static io.swagger.v3.jaxrs2.integration.ServletConfigContextUtils.OPENAPI_CONFIGURATION_FILTER_KEY;
import static io.swagger.v3.jaxrs2.integration.ServletConfigContextUtils.OPENAPI_CONFIGURATION_OBJECT_MAPPER_PROCESSOR_KEY;
import static io.swagger.v3.jaxrs2.integration.ServletConfigContextUtils.OPENAPI_CONFIGURATION_DEFAULT_RESPONSE_CODE_KEY;
import static io.swagger.v3.jaxrs2.integration.ServletConfigContextUtils.OPENAPI_CONFIGURATION_OPENAPI_31_KEY;
import static io.swagger.v3.jaxrs2.integration.ServletConfigContextUtils.OPENAPI_CONFIGURATION_CONVERT_TO_OPENAPI_31_KEY;
import static io.swagger.v3.jaxrs2.integration.ServletConfigContextUtils.OPENAPI_CONFIGURATION_PRETTYPRINT_KEY;
Expand Down Expand Up @@ -65,6 +66,7 @@ public OpenAPIConfiguration load(String path) throws IOException {
.cacheTTL(getLongInitParam(servletConfig, OPENAPI_CONFIGURATION_CACHE_TTL_KEY))
.scannerClass(getInitParam(servletConfig, OPENAPI_CONFIGURATION_SCANNER_KEY))
.objectMapperProcessorClass(getInitParam(servletConfig, OPENAPI_CONFIGURATION_OBJECT_MAPPER_PROCESSOR_KEY))
.defaultResponseCode(getInitParam(servletConfig, OPENAPI_CONFIGURATION_DEFAULT_RESPONSE_CODE_KEY))
.openAPI31(getBooleanInitParam(servletConfig, OPENAPI_CONFIGURATION_OPENAPI_31_KEY))
.convertToOpenAPI31(getBooleanInitParam(servletConfig, OPENAPI_CONFIGURATION_CONVERT_TO_OPENAPI_31_KEY))
.modelConverterClasses(resolveModelConverterClasses(servletConfig));
Expand Down Expand Up @@ -138,6 +140,9 @@ public boolean exists(String path) {
if (getInitParam(servletConfig, OPENAPI_CONFIGURATION_OBJECT_MAPPER_PROCESSOR_KEY) != null) {
return true;
}
if (getInitParam(servletConfig, OPENAPI_CONFIGURATION_DEFAULT_RESPONSE_CODE_KEY) != null) {
return true;
}
if (getInitParam(servletConfig, OPENAPI_CONFIGURATION_CONVERT_TO_OPENAPI_31_KEY) != null) {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class SwaggerLoader {
private String openapiAsString;

private String objectMapperProcessorClass;
private String defaultResponseCode;
private String modelConverterClasses;

private Boolean sortOutput = false;
Expand All @@ -62,6 +63,20 @@ public void setObjectMapperProcessorClass(String objectMapperProcessorClass) {
this.objectMapperProcessorClass = objectMapperProcessorClass;
}

/**
* @since 2.2.17
*/
public String getDefaultResponseCode() {
return defaultResponseCode;
}

/**
* @since 2.2.17
*/
public void setDefaultResponseCode(String defaultResponseCode) {
this.defaultResponseCode = defaultResponseCode;
}

/**
* @since 2.0.6
*/
Expand Down Expand Up @@ -279,6 +294,7 @@ public Map<String, String> resolve() throws Exception{
.resourceClasses(resourceClassesSet)
.resourcePackages(resourcePackagesSet)
.objectMapperProcessorClass(objectMapperProcessorClass)
.defaultResponseCode(defaultResponseCode)
.modelConverterClasses(modelConverterSet)
.sortOutput(sortOutput)
.alwaysResolveAppPath(alwaysResolveAppPath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import io.swagger.v3.jaxrs2.matchers.SerializationMatchers;
import io.swagger.v3.jaxrs2.petstore31.PetResource;
import io.swagger.v3.jaxrs2.petstore31.TagResource;
import io.swagger.v3.jaxrs2.resources.DefaultResponseResource;
import io.swagger.v3.jaxrs2.resources.Misc31Resource;
import io.swagger.v3.jaxrs2.resources.ParameterMaximumValueResource;
import io.swagger.v3.jaxrs2.resources.ResponseReturnTypeResource;
Expand Down Expand Up @@ -3148,6 +3149,27 @@ public void testResponseReturnType() {
SerializationMatchers.assertEqualsToYaml(openAPI, yaml);
}

@Test(description = "Responses Default Status")
public void testResponseDefaultStatus() {
SwaggerConfiguration config = new SwaggerConfiguration().defaultResponseCode("200");
Reader reader = new Reader(config);

OpenAPI openAPI = reader.read(DefaultResponseResource.class);
String yaml = "openapi: 3.0.1\n" +
"paths:\n" +
" /:\n" +
" get:\n" +
" operationId: test\n" +
" responses:\n" +
" \"200\":\n" +
" description: default response\n" +
" content:\n" +
" '*/*':\n" +
" schema:\n" +
" type: string\n";
SerializationMatchers.assertEqualsToYaml(openAPI, yaml);
}

@Test
public void test4412PathWildcards() {
Reader reader = new Reader(new OpenAPI());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.swagger.v3.jaxrs2.resources;

import javax.ws.rs.GET;
import javax.ws.rs.Path;

public class DefaultResponseResource {

@GET
@Path("/")
public String test() {
return null;
}

}
2 changes: 2 additions & 0 deletions modules/swagger-maven-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ Parameter | Description | Required | Default
`readAllResources`|see [configuration property](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false|
`ignoredRoutes`|see [configuration property](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false|
`objectMapperProcessorClass`|see [configuration property](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false|
`defaultResponseCode`|see [configuration property](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false|
`modelConverterClasses`|see [configuration property](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false|
`contextId`|see [Context](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#context)|false|${project.artifactId}

Expand All @@ -208,3 +209,4 @@ Since version 2.1.6, `sortOutput` parameter is available, allowing to sort objec
Since version 2.1.6, `objectMapperProcessorClass` allows to configure also the ObjectMapper instance used to serialize the resolved OpenAPI
Since version 2.1.9, `alwaysResolveAppPath` parameter is available, allowing to trigger resolving of Application Path from annotaion also not in runtime (e.g. using servlet in separate application, or in maven plugin at build time, etc)
Since version 2.1.15, `skipResolveAppPath` parameter is available, allowing to skip resolving of Application Path from annotation
Since version 2.2.17, `defaultResponseCode` parameter is available, allowing to set the code used when resolving responses with no http status code annotation
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,9 @@ private SwaggerConfiguration mergeConfig(OpenAPI openAPIInput, SwaggerConfigurat
if (StringUtils.isNotBlank(objectMapperProcessorClass)) {
config.objectMapperProcessorClass(objectMapperProcessorClass);
}
if (StringUtils.isNotBlank(defaultResponseCode)) {
config.defaultResponseCode(defaultResponseCode);
}
if (isCollectionNotBlank(modelConverterClasses)) {
config.modelConverterClasses(modelConverterClasses);
}
Expand Down Expand Up @@ -385,6 +388,11 @@ private boolean isCollectionNotBlank(Collection<?> collection) {
*/
@Parameter( property = "resolve.objectMapperProcessorClass" )
private String objectMapperProcessorClass;
/**
* @since 2.2.17
*/
@Parameter( property = "resolve.defaultResponseCode" )
private String defaultResponseCode;
@Parameter(property = "resolve.prettyPrint")
private Boolean prettyPrint;
@Parameter(property = "resolve.readAllResources")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,17 @@ public ApiResponses addApiResponse(String name, ApiResponse item) {
*
* @return ApiResponse _default
**/

@Deprecated
public ApiResponse getDefault() {
return this.get(DEFAULT);
}

@Deprecated
public void setDefault(ApiResponse _default) {
addApiResponse(DEFAULT, _default);
}

@Deprecated
public ApiResponses _default(ApiResponse _default) {
setDefault(_default);
return this;
Expand Down

0 comments on commit fab5000

Please sign in to comment.