Spring Boot with Swagger 2 - spring-boot

I'm trying to use #SwaggerDefinition in my sample Spring Boot REST API. I'm using springfox-swagger2 version 2.6.1
I have annotated my Product model with #ApiModelProperty and the endpoints with #ApiOperation. I'm able to view the end point and model documentations.
But the #SwaggerDefinition are not getting generated.
I have created the following SwaggerConfig:
#Configuration
#EnableSwagger2
#SwaggerDefinition(
info = #io.swagger.annotations.Info(
description = "Spring Boot Product Store API",
version = "V1.2.3",
title = "API of a Spring Boot product store",
termsOfService = "share and care",
contact = #io.swagger.annotations.Contact(name = "John Pack",
email = "john#productsample.com ", url =
"http://productsample.com"),
license = #io.swagger.annotations.License(name = "Apache 2.0",
url = "http://www.apache.org")
)
)
public class SwaggerConfig {
#Bean
public Docket productApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("pkg.controllers"))
.paths(regex("/product.*"))
.build();
}
}
What else needs to be done for #SwaggerDefinition documentations? Thanks in advance

Related

Remove Controller Name in Swagger UI

Is there any way to hide the controller name in the swagger-ui.
My class is like this. I do not want my controller name on the ui.
#Api(tags = {"group"})
public class MyControllerName {}
I did check some existing answers. for ex: How to remove controller list from Swagger UI did not help at all.
Create Docket bean and assign to it custom ApiInfo object, in this way:
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.controller"))
.paths(PathSelectors.ant("/foos/*"))
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfo(
"My REST API",
"Some custom description of API.",
"API TOS",
"Terms of service",
new Contact("John Doe", "www.example.com", "myeaddress#company.com"),
"License of API", "API license URL", Collections.emptyList());
}
You can exclude any controller:
import { Controller, Get } from '#nestjs/common';
import { ApiExcludeController } from '#nestjs/swagger';
import { AppService } from './app.service';
#ApiExcludeController()
#Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
#Get()
getHello(): string {
return this.appService.getHello();
}
}
This sould be good feature request to springfox team. If you need to customize the swagger-UI you should be doing it on your own.
Maybe the below steps are useful for someone.
Go to https://github.com/swagger-api/swagger-ui
Download the latest code
customize whatever you want to customize
package either as a web jar or as resources in your application
create resource handler mapping if required
Refer - https://github.com/springfox/springfox/issues/1108

How to add custom Springdoc resources to swagger-ui page

I'm not good at swagger and related libraries, so sorry if the title is confusing.
I have several services which provide their api as swagger documentation in json format and via swagger-ui. Next, I have a springboot service which is a proxy of the previously mentioned services and it provides combined api of all services (one can select exact service in a dropdown). It was implemented like this:
public class PropertyResourceProvider implements SwaggerResourcesProvider {
#Autowired
private SwaggerConfigProperties swaggerConfigProperties; // Just a mapping of config
#Override
public List<SwaggerResource> get() {
// Doc for local (proxy) service
val local = new SwaggerResource();
local.setName(title);
local.setUrl(swaggerLocal);
local.setSwaggerVersion(version);
// Add other services - specified in config
List<SwaggerResource> services = swaggerConfigProperties.getServices().stream().map(service -> {
String contextPath = service.get("contextPath");
String externalPath = SWAGGER_DOC_BASE_PATH + "/" + contextPath;
val resource = new SwaggerResource();
resource.setName(service.get("name"));
resource.setUrl(externalPath);
resource.setSwaggerVersion(service.get("version"));
return resource;
}).collect(Collectors.toList());
services.add(local);
return services; // Return combined API
}
Now, we're moving from springfox to springdoc and I can't use SwaggerResource and SwaggerResourcesProvider. How can I implements the same using springdoc?

Mandatory header for all API in openapi 3.0

I am using OpenAPI 3.0 with Spring-boot 5 and therefore have no configuration YAML. I have a header that contains the client Identification ID(This is not an authentication header). I want to make that a mandatory header param. Added below OpenAPI configuration
#Configuration
public class OpenAPIConfiguration {
#Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.components(new Components()
.addParameters("myCustomHeader", new Parameter().in("header").schema(new StringSchema()).required(true).description("myCustomHeader").name("myCustomHeader")))
.info(new Info()
.title("My Rest Application")
.version("1.2.26"));
}
}
However, the swagger UI does not show the required param in any API. Can someone help as to what I am doing wrong?
Adding parameter definition to a custom OpenAPI bean will not work because the parameter won't get propagated to the operations definitions. You can achieve your goal using OperationCustomizer:
#Bean
public OperationCustomizer customize() {
return (operation, handlerMethod) -> operation.addParametersItem(
new Parameter()
.in("header")
.required(true)
.description("myCustomHeader")
.name("myCustomHeader"));
}
The OperationCustomizer interface was introduced in the springdoc-openapi 1.2.22. In previous versions you would need to use OpenApiCustomiser:
#Component
public class MyOpenApiCustomizer implements OpenApiCustomiser {
private static final List<Function<PathItem, Operation>> OPERATION_GETTERS = Arrays.asList(
PathItem::getGet, PathItem::getPost, PathItem::getDelete, PathItem::getHead,
PathItem::getOptions, PathItem::getPatch, PathItem::getPut);
private Stream<Operation> getOperations(PathItem pathItem) {
return OPERATION_GETTERS.stream()
.map(getter -> getter.apply(pathItem))
.filter(Objects::nonNull);
}
#Override
public void customise(OpenAPI openApi) {
openApi.getPaths().values().stream()
.flatMap(this::getOperations)
.forEach(this::customize);
}
private void customize(Operation operation) {
operation.addParametersItem(
new Parameter()
.in("header")
.required(true)
.description("myCustomHeader")
.name("myCustomHeader"));
}
}

error when using my own input with swagger 2 and spring boot 2

I'm new to spring boot and trying to set up a swagger documentation for a web app I'm working on. It works quite well when my endpoints only require strings, list or other basic request bodies but whenever I use custom inputs I get this error : could not resolve reference because of could not resolve pointer does not exist in document
the error
I created a small project with just one end point to search more easily. Those are my swagger dependencies :
compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'
Here is the swagger config :
#Configuration
#EnableSwagger2
class SwaggerConfig {
#Bean
Docket productApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("io.example.bss.testswagger"))
.paths(any())
.build()
.apiInfo(metaInfo())
}
private ApiInfo metaInfo() {
ApiInfo apiInfo = new ApiInfo(
"API",
"A description",
"0.0.1",
"urn:tos",
new Contact("someone", "https://www.google.com",
"an.email#gmail.com"),
"",
"",
new ArrayList<VendorExtension>()
)
return apiInfo
}
}
Then there is the controller :
#Controller
class ControllerHello {
#PostMapping("/")
def hello(#RequestBody Profile profile){
return "hello $profile.name $profile.surname, I see you're $profile.age years old"
}
}
And finally,the DTO :
#ApiModel(value = "the profile containing the name surname and age of a person")
#Document
class Profile {
#ApiModelProperty(notes = "the name of the person", required = true)
String name
#ApiModelProperty(notes = "the surname of the person", required = true)
String surname
#ApiModelProperty(notes = "the age of the person", required = true)
int age
}
In a similar post someone was advised to use alternateTypeRules in Docket, but I'm not sure it would work for my issue and I don't know how to set it up.
It turns out that swagger-ui was having trouble because my Profile class was written in groovy and it was taking the metaclass into account when displaying the model.
The problem was solved by adding this line .ignoredParameterTypes(groovy.lang.MetaClass.class) like so :
#Bean
Docket productApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("io.example.bss.testswagger"))
.paths(any())
.build()
.apiInfo(metaInfo())
.ignoredParameterTypes(groovy.lang.MetaClass.class)
}
This is my source: https://github.com/springfox/springfox/issues/752

how to change the #FeignClient name in runtime

I use Spring Cloud Netflix to build my micro service .
#FeignClient(name = "ms-cloud",configuration = MsCloudClientConfig.class)
public interface TestClient {
/**
* #return
*/
#RequestMapping(value = "/test", method = RequestMethod.GET)
String test();
}
I want to change the name to ms-cloud-pre when some special user.
Anyone can give some advice?
According to the documentation feign supports placeholders in the name and url fields.
#FeignClient(name = "${store.name}")
public interface StoreClient {
//..
}
So you could set store.name=storeProd at runtime using normal spring boot configuration mechanisms.
To create a spring-cloud Feign client at runtime in situations where you don't know the service-id until the point of call:
import org.springframework.cloud.openfeign.FeignClientBuilder;
#Component
public class InfoFeignClient {
interface InfoCallSpec {
#RequestMapping(value = "/actuator/info", method = GET)
String info();
}
FeignClientBuilder feignClientBuilder;
public InfoFeignClient(#Autowired ApplicationContext appContext) {
this.feignClientBuilder = new FeignClientBuilder(appContext);
}
public String getInfo(String serviceId) {
InfoCallSpec spec =
this.feignClientBuilder.forType(InfoCallSpec.class, serviceId).build();
return spec.info();
}
}
That actually is possible. In Spring Cloud Zookeeper we're doing a similar thing since the name of the service in the Feign client is not the one that is there in the in Zookeeper. It can be an alias presented in the yaml file. Here you have the code example https://github.com/spring-cloud/spring-cloud-zookeeper/blob/master/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/dependency/DependencyRibbonAutoConfiguration.java#L54 and here you have the description of the dependencies feature - https://github.com/spring-cloud/spring-cloud-zookeeper/blob/master/docs/src/main/asciidoc/spring-cloud-zookeeper.adoc#using-the-zookeeper-dependencies

Resources