How to set OpenApi config via code and not using annotation in Micronaut - swagger-ui

I have a springboot application and I want to convert to Micronaut, but how I config the openapi via code, like in this article
https://keepgrowing.in/java/springboot/how-to-secure-spring-boot-swagger-ui-with-basic-authentication/
Code snippet:
#Configuration
public class OpenApiConfig {
#Bean
public OpenAPI customOpenAPI(OpenApiProperties properties) {
var openApi = new OpenAPI()
.info(getInfo(properties));
return openApi;
}
private Info getInfo(OpenApiProperties properties) {
return new Info()
.title(properties.getProjectTitle())
.description(properties.getProjectDescription())
.version(properties.getProjectVersion())
.license(getLicense());
}
private License getLicense() {
return new License()
.name("Unlicense")
.url("https://unlicense.org/");
}
}
Currently, I have already done the ff:
Replace #Bean as #Singleton, Failed
Adding #Factory to the class, Failed
** The application compiles, but on run time the OpenApi definition is not set on the swagger ui

Micronaut generates the Open-API definition at the compilation time, so it's not possible to have dynamic properties. The only way is to set those values is to use annotations https://micronaut-projects.github.io/micronaut-openapi/latest/guide/index.html

Related

OpenAPI, contract-first with Springdoc and multiple specs

I am trying to port a Swagger UI from Springfox to Springdoc.
The Swagger UI is generated via Maven plugin
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
... from two different OpenAPI specifications, both implemented in the same Spring Boot application. We use two different specs for two different clients.
So far, my Swagger UI looked like this with Springfox. Note the drop-down list that allows to choose the spec to display.
Now, with Springdoc 1.6.6, the Swagger-UI looks like this.
Note that:
The default landing page is the sample Pet Store and none of my specifications, although I specified in my Spring Boot's application.yaml:
springdoc:
swagger-ui:
disable-swagger-default-url: true
No drop-down
I have to manually enter my specification's name into the "Explore" text field in order to see its Swagger UI
I tried addressing the missing drop-down by following I have installed OpenAPI 3 using springdoc, but the URL is strange. Can I change it to the expected value?, which claims to display a drop-down, but to no avail.
My questions:
How do I display the drop-down? Does Springdoc support it at all out-of-the-box?
Apparently, accessing http://localhost:8080/swagger-ui/index.html?urls.primaryName=Information makes the drop-down list of specs magically appear.
How do I make sure that the default URL http://localhost:8080/swagger-ui/index.html lands on one of my specs, and not on the Pet Store?
Here is btw. my Bean configuration:
#Configuration
public class SwaggerDocumentationConfig {
/**
* Path of the OpenAPI package extracted out of a random class in that package
*/
private static final String INFORMATION_PACKAGE = InformationApi.class.getPackageName();
/**
* Path of the OpenAPI package extracted out of a random class in that package
*/
private static final String OPERATIONS_PACKAGE = OperationsApi.class.getPackageName();
private GroupedOpenApi getBaseApiDoc(String groupName, String packagePath) {
return GroupedOpenApi.builder()
.group(groupName)
.packagesToScan(packagePath)
.build();
}
#Bean
public GroupedOpenApi getOperationsApiDoc() {
return getBaseApiDoc("Operations", OPERATIONS_PACKAGE);
}
#Bean
public GroupedOpenApi getInfoApiDoc() {
return getBaseApiDoc("Information", INFORMATION_PACKAGE);
}
#Bean
public OpenAPI springShopOpenAPI() {
return new OpenAPI()
.info(new Info().title("SpringShop API")
.description("Spring shop sample application")
.version("v0.0.1")
.license(new License().name("Apache 2.0").url("http://springdoc.org")))
.externalDocs(new ExternalDocumentation()
.description("SpringShop Wiki Documentation")
.url("https://springshop.wiki.github.org/docs"));
}}

Smallrye open api interceptor

I am developing a rest application.
Some endpoints require a custom header parameter, not related to authorisation. I created a custom annotation using jax-rs NameBinding. Here is an usage example:
#GET
#RequiresBankHeader
public int get(
#HeaderParam("bank")
#Parameter(ref = "#/components/parameters/banks")
String bank) {
return someService.getSomeInformation();
}
There is a provider that intercepts this call and do some routine using the information in the header parameter.
The problem is that I have to repeat '#HeaderParam("bank") #Parameter(ref = "#/components/parameters/banks") String bank' everywhere, just so it appears in Swagger, even though the service classes do not need it. I was able to at least reuse the parameter definition with ref = "#/components/parameters/banks", and declaring it in the OpenAPI.yml file, that Quarkus merges with generated code very nicely.
But I also want to create and interceptor to dynamically add this do the OpenApi definition whenever RequiresBankHeader annotation is present.
Is there a way to do it?
I dont think you can use interceptors to modify the generated Openapi schema output.
If all methods on a given endpoint require some parameter, you can specify it on class level like so:
#Path("/someendpoint")
public class MyEndpoint {
#HeaderParam("bank")
#Parameter(name = "bank")
String bank;
#GET
public Response getAll() {return Response.ok().build()}
#GET
#Path("{id}")
public Response someMethod(#PathParam("id") String id) {return Response.ok().build();}
}
As mentioned by Roberto Cortez, the MP OpenAPI spec provides a programmatic way to contribute metadata to the openapi.yml file.
It is not possible to detect an annotation in the JAX-RS endpoint definition, but it was good enough to automate what I needed. Since all methods that had the RequiresBankHeader return the same Schema, I was able to hack it like this:
public class OpenApiConfigurator implements OASFilter {
#Override
public Operation filterOperation(Operation operation) {
operation.getResponses().getAPIResponses().values().stream().
map(APIResponse::getContent).
filter(Objects::nonNull).
map(Content::getMediaTypes).
flatMap(mediaTypes -> mediaTypes.values().stream()).
map(MediaType::getSchema).
filter(Objects::nonNull).
map(Schema::getRef).
filter(Objects::nonNull).
filter(ref -> ref.contains("the common response schema")).
findAny().
ifPresent(schema -> {
ParameterImpl parameter = new ParameterImpl();
parameter.setRef("#/components/parameters/banks");
operation.addParameter(parameter);
});
return operation;
}
OpenApiConfigurator should be configure in the application properties, using mp.openapi.filter=com.yourcompany.OpenApiConfigurator

How to use custom processor on spring cloud data flow?

Here is the Stream I intend to implement:
It is supposed to read records from jdbc, transform to json and write on another database thru jdbc.
For this I have implemented (using the new functional approach):
#SpringBootApplication
public class StreamAppApplication {
private static ObjectMapper objectMapper;
public static void main(String[] args) {
SimpleModule module = new SimpleModule();
module.addSerializer(new ResultSetSerializer());
objectMapper = new ObjectMapper().registerModule(new ParameterNamesModule())
.registerModule(new Jdk8Module())
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.registerModule(module);
SpringApplication.run(StreamAppApplication.class, args);
}
#Bean
public Function<ResultSet, String> recordToJson() {
return value -> {
try {
return objectMapper.writeValueAsString(value);
} catch (JsonProcessingException e) {
throw new IllegalStateException("Falha conversão json", e);
}
};
}
}
On the application.properties
spring.cloud.stream.function.definition=recordToJson
Then I have imported it on the web UI as app of type TRANSFORM. It appeared on the UI with the transform classification and no parameters.
How do I use it?
You may want to review and follow the function-bindings recipe from the Microsite to get an understanding of what needs explicitly configured.
From what I can tell, you're likely missing the binding configuration for how your custom processor needs to consume and produce to the relevant channels.
Perhaps even repeat the samples from the recipe on your environment to get an understanding of how it comes together. With that then, you will be able to adapt your custom processor in the same data pipeline to validate it.

Using openapi.yaml in springdoc

I can customize OpenAPI from code.
Can I do same over openapi.yaml like swagger-petstore
I create simple springboot project with one #RestController.
I create openapi.yaml and copy it to /src/main/resources/.
But I see default values on open swagger-ui page.
This is available from the FAQ page in the spring-doc documentation.
See What is a proper way to set up Swagger UI to use provided spec.yml? and How can use custom json/yml file instead of generated one ? of the same page.
Example from the FAQ page
Turn off auto-generation in the project property file springdoc.api-docs.enabled=false
Put your yaml file in src/main/resources/static such as src/main/resources/static/myApiFile.yaml
Set the swagger-ui url for the file springdoc.swagger-ui.url=/myApiFile.yaml
Enable the minimal beans configuration
import org.springdoc.core.SpringDocConfigProperties;
import org.springdoc.core.SpringDocConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class SpringDocsConfiguration {
#Bean
SpringDocConfiguration springDocConfiguration() {
return new SpringDocConfiguration();
}
#Bean
public SpringDocConfigProperties springDocConfigProperties() {
return new SpringDocConfigProperties();
}
}
The code below is all what we needed to do to use openapi.yaml specification file instead of the default one that is generated from code.
Explanation:
org.springdoc.webflux.api.OpenApiResource is Controller that handles /v3/api-docs and /v3/api-docs.yaml endpoints. Swagger UI is using that endpoint to show swagger ui page - /swagger-ui.html. You can see the configuration when you hit /v3/api-docs/swagger-config endpoint.
org.springdoc.webflux.api.OpenApiResource bean is registered only if missing. You can see it in SpringDocWebFluxConfiguration. The method that creates the bean is annotated with #ConditionalOnMissingBean. So you just need to extend it and adjust OpenApi specification retrieval (see below).
org.springdoc.webflux.api.OpenApiResource is using getOpenApi() method to retrieve OpenAPI specification (by default the specification is generated based on the class annotation from code). So you just need to override getOpenApi() method and provide the specification from yaml file itself (getYamlMapper() method is also provided for you in the parent classes, so it's really that easy how it is in the file below)
You can see OpenApiResource is in webflux package because we use org.springdoc:springdoc-openapi-webflux-ui, Spring WebFlux. It is done similarly in Spring MVC.
Hope this helps :) When you hit /swagger-ui.html you should see the docs directly from .yaml spec. When you hit /v3/api-docs you should see the specs itself in JSON. When you hit /v3/api-docs.yaml you should see the specs itself in YAML. No Spring Configuration code is needed. Just the controller as you see below :)
Just to be clear. Our OpenAPI spec is in src/main/resources/openapi/api.yaml
package com.your.package;
...imports omitted for readability...
import org.springdoc.webflux.api.OpenApiResource;
#RestController
public class OpenApiController extends OpenApiResource {
#Value("classpath:openapi/api.yaml")
private Resource openAPIResource;
private OpenAPI openAPI;
public OpenApiController(ObjectFactory<OpenAPIBuilder> openAPIBuilderObjectFactory, AbstractRequestBuilder requestBuilder, GenericResponseBuilder responseBuilder, OperationBuilder operationParser, RequestMappingInfoHandlerMapping requestMappingHandlerMapping, Optional<List<OperationCustomizer>> operationCustomizers, Optional<List<OpenApiCustomiser>> openApiCustomisers, SpringDocConfigProperties springDocConfigProperties, Optional<ActuatorProvider> actuatorProvider) {
super(openAPIBuilderObjectFactory, requestBuilder, responseBuilder, operationParser, requestMappingHandlerMapping, operationCustomizers, openApiCustomisers, springDocConfigProperties, actuatorProvider);
}
#SneakyThrows
#PostConstruct
public void initOpenAPI() {
openAPI = getYamlMapper().readValue(openAPIResource.getInputStream(), OpenAPI.class);
}
#Override
protected synchronized OpenAPI getOpenApi() {
return openAPI;
}
}
If you need configuration file, you can have a look at the FAQ, documentation:
https://springdoc.org/faq.html#can-i-use-spring-property-with-swagger-annotations
And here is the link for code samples:
https://raw.githubusercontent.com/springdoc/springdoc-openapi/master/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app15/SpringDocApp15Test.java

Swagger 2.0 where to declare Basic Auth Schema

How do I define basic authentication using Swagger 2.0 annotations and have it display in swagger UI.
In the resource I have:
#ApiOperation(value = "Return list of categories", response=Category.class, responseContainer="List", httpMethod="GET", authorizations = {#Authorization(value="basicAuth")})
public Response getCategories();
I looked here:
https://github.com/swagger-api/swagger-core/wiki/Annotations#authorization-authorizationscope
And it says "Once you've declared and configured which authorization schemes you support in your API, you can use these annotation to note which authorization scheme is required on a resource or a specific operation" But I can't find anything that talks about where to declare and configure the authorization schemes.
Update:
I found code on how to declare the schema, but I still do not see any information about the authentication schema in the UI. I'm not sure what I am missing
#SwaggerDefinition
public class MyApiDefinition implements ReaderListener {
public static final String BASIC_AUTH_SCHEME = "basicAuth";
#Override
public void beforeScan(Reader reader, Swagger swagger) {
}
#Override
public void afterScan(Reader reader, Swagger swagger) {
BasicAuthDefinition basicAuthDefinition = new BasicAuthDefinition();
swagger.addSecurityDefinition(BASIC_AUTH_SCHEME, basicAuthDefinition);
}
}
Using Springfox 2.6 annotations, you must first define Basic authentication as one of the security schemes when you set up the Docket in your configuration, like this:
List<SecurityScheme> schemeList = new ArrayList<>();
schemeList.add(new BasicAuth("basicAuth"));
return new
Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo)
.securitySchemes(schemeList)
...
Then you can use the Springfox annotations in your service to set Basic Auth for the operation for which you want to require authentication:
#ApiOperation(value = "Return list of categories", response=Category.class, responseContainer="List", httpMethod="GET", authorizations = {#Authorization(value="basicAuth")})
public Response getCategories();
I struggeled with this as well. In my case i used the swagger-maven-plugin. To solve this i added this within the maven plugin:
<securityDefinitions>
<securityDefinition>
<name>basicAuth</name>
<type>basic</type>
</securityDefinition>
</securityDefinitions>
After that i was able to add it on my resource like this:
#Api(value = "My REST Interface", authorizations = {#Authorization(value="basicAuth")})
The generated json included the security element for each endpoint:
"security":[{
"basicAuth" : []
}]
And the security definition:
"securityDefinitions" : {
"basicAuth" : {
"type" : "basic"
}
}
I hope this helps others as well.
You can use the #SwaggerDefinition
http://swagger.io/customizing-your-auto-generated-swagger-definitions-in-1-5-x/
or you can configure the swagger object directly, here's an example
http://www.programcreek.com/java-api-examples/index.php?source_dir=rakam-master/rakam/src/main/java/org/rakam/WebServiceRecipe.java

Resources