Use case: We have an application built on CAP Java and unlike traditional CAP structure we have implemented RestController for consuming data from SAP Event Mesh queue using webhook. To develop and describe this api we wanted to implement Swagger.
Our CAP App is on Springboot 3.* and we have tried to implement Swagger3(Open api) for the same. Below are the detailed steps:
Add openapi dependancy in your pom.xml
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.2.0</version>
</dependency>
Add a SwaggerResourceConfig to add the swagger registry:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/swagger/**")
.addResourceLocations("classpath:/swagger/");
}
Create a swagger folder inside your resources folder.
Also in the WebSecurityConfiguration include swagger-ui path.
In your RestController api:-
An example:
@Operation(summary = "Post Data to monitoring")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Data has been consumed successfully", content = {
@Content(mediaType = "application/json", schema = @Schema(implementation = IntegrationExecution.class)) }),
@ApiResponse(responseCode = "500", description = "TaskRejectException", content = @Content) })
To add authorization & authentication if required on the api, use the Security Schemes from openapi (more information can be found here: https://swagger.io/docs/specification/authentication/)
In our case we explored APIKey, add the below Bean in your Swagger Config class:
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI().info(new Info().title("MIS")
.version("1.0.0"))
.components(new Components().addSecuritySchemes("Authorization",
new SecurityScheme().type(SecurityScheme.Type.APIKEY)
.in(SecurityScheme.In.HEADER)
.name("Authorization")))
.addSecurityItem(new SecurityRequirement().addList("Authorization"));
}
With this change, once you build your application using maven an output file called openapi.json should be created in the swagger folder.
When the application is started, you should be able to access the swagger here: http://localhost:8080/swagger-ui/index.html
However if the defined request body schema for the api has Associations/Compositions in the cds (like in our case), the request body displayed will contain all the details which might not be always useful and same details will be shown in input example.
To control this properly there is another way to implement openapi if you have a complex schema however all the information is not required to be shared in example and in request body schema structure.
Second Option:
Add the swagger folder in resources folder
Add swagger-codegen-maven-plugin in your pom.xml:
<plugin>
<groupId>io.swagger.codegen.v3</groupId>
<artifactId>swagger-codegen-maven-plugin</artifactId>
<version>3.0.33</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/swagger/openapiInput.json</inputSpec>
<!-- Use 'openapi-yaml' to get resolved YAML or 'openapi' to get resolved JSON -->
<language>openapi</language>
<!-- Default is ${project.build.directory}/generated-sources/swagger -->
<output>${project.basedir}/src/main/resources/swagger/</output>
<configOptions>
<!-- Default output file name is 'openapi.yaml' or 'openapi.json' -->
<outputFile>openapi.json</outputFile>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
Based on your requirement, you can define the openapiInput spec. (Hint: Use https://editor.swagger.io/ to create the inputspec yaml/json)
You can also explore other Authentication & Authorization security schemes from openapi and define the request body schema with an example as per your requirement.
A sample Inputspec:
{
"openapi": "3.0.2",
"info": {
"title": "Swagger-CAP Java",
"description": "Swagger implementation for CAP JAVA MVC",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"email": "[email protected]"
},
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
},
"version": "1.0.11"
},
"servers": [
{
"url": "http://localhost:8080"
}
],
"tags": [
{
"name": "postData",
"description": "Post data to sample app"
}
],
"paths": {
"/webhook": {
"post": {
"tags": [
"postData"
],
"summary": "Add post data to sample app",
"description": "Add post data to sample app",
"operationId": "postData",
"requestBody": {
"description": "Create a new post record",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RequestBody"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful operation",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RequestBody"
}
}
}
},
"500": {
"description": "TaskRejectException"
}
},
"security": [
{
"ApiKey_auth": [
"write:postData"
],
"oauth2": [
"write:postData"
]
}
]
}
}
},
"components": {
"schemas": {
"RequestBody": {
"type": "object",
"properties": {
"keyID": {
"type": "string",
"format": "UUID"
},
"key_code": {
"type": "string",
"example": "S- Scheduled/ M- Manual"
},
"status_code": {
"type": "string",
"example": "C- Completed/ D- Errors/ F- Failed"
},
"startRunTimestamp": {
"type": "date-time"
},
"logs": {
"$ref": "#/components/schemas/Logs"
},
"errors": {
"$ref": "#/components/schemas/Errors"
},
"reports": {
"$ref": "#/components/schemas/reports"
}
}
},
"reports": {
"type": "object",
"example": "UUID"
},
"Logs": {
"type": "object",
"properties": {
"logTimestamp": {
"type": "date-time"
},
"logMessage": {
"type": "string"
},
"logLevel_code": {
"type": "string",
"example": "I- Info/ W- Warning/ E- Error"
}
}
},
"Errors": {
"type": "object",
"properties": {
"errorType_ID": {
"type": "string",
"example": "D - Data Error/ I - Integration Error"
},
"errorCode": {
"type": "integer"
},
"errorDescription": {
"type": "string"
},
"errorCategory_ID": {
"type": "string",
"example": "SCRIPT_RUNTIME_ERROR"
},
"errorTimestamp": {
"type": "date-time"
},
"reportID": {
"type": "string",
"format": "UUID"
}
}
}
},
"securitySchemes": {
"ApiKey_auth": {
"type": "apiKey",
"name": "Authorization",
"in": "header"
},
"oauth": {
"type": "oauth2",
"flows": {
"clientCredentials": {
"tokenUrl": <URL>,
"scopes": {
"write:postData": "add records in sample app"
}
}
}
}
}
}
}
Once the input file is compiled, an output file : openapi.json will be generated.
On running the application, you should be able to access swagger: http://localhost:8080/swagger-ui/index.html. Search for /swagger/openapi.json