3

Swagger Implementation for CAP Java for MVC

 11 months ago
source link: https://blogs.sap.com/2023/10/12/swagger-implementation-for-cap-java-for-mvc/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
October 12, 2023 3 minute read

Swagger Implementation for CAP Java for MVC

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:

Option 1:

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:-

  1. Add the annotation to describe your api
  2. Api responses expected
  3. Request body schema

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.

Option 2:

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK