Spring boot 3 + Swagger not working with updated version - java

Trying to generate swagger UI but not able to generate using spring boot 3.0.2 and java 17.0.2. Below is my details
Gradle dependency
implementation "io.springfox:springfox-boot-starter:3.0.0"
Swagger Configuration
#SpringBootApplication
#ComponentScan({"com.bl.*"})
#EnableJpaRepositories(basePackages = { "com.bl.entity.repository" })
#EntityScan({"com.bl.entity"})
public class BlApiUiApplication {
public static void main(String[] args) {
SpringApplication.run(BlApiUiApplication.class, args);
}
#Bean
Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("UI Details")
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("API")
.description("UI")
.licenseUrl("URL").version("1.0").build();
}
}
Controller
#RestController
#RequestMapping("/v0")
#Api(value = "API")
public class UIController {
private final Logger logger = LoggerFactory.getLogger(UIController.class);
#ApiOperation(value = "isRunning", notes = "To check whether service is running or not")
#GetMapping(value = "/isRunning", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> test() {
return new ResponseEntity<>("Service is running.", HttpStatus.OK);
}
#ApiOperation(value = "/user/login", notes = "To login user")
#ApiResponses(value = { #ApiResponse(code = 200, message = "Successful"),
#ApiResponse(code = 500, message = "Internal server error"),
#ApiResponse(code = 1001, message = "Application specific error.") })
#PostMapping(value = "/user/login", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<BaseGatewayResponse> login(#RequestBody final UserLoginRequest requestDTO) {
logger.info("Login request: {}", requestDTO);
UserLoginResponse responseDTO = userGatewayService.login(requestDTO);
logger.info("Exit Login response: {} for request: {}", responseDTO, requestDTO);
return new ResponseEntity<>(responseDTO, HttpStatus.OK);
}
After running its not working getting below error.
Swagger URL : http://localhost:8080/BLApiUI/swagger-ui/index.html
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Fri Feb 03 22:59:52 IST 2023
There was an unexpected error (type=Not Found, status=404).

in case you want to try "openapi", simply add annotation "OpenAPIDefinition" to Application class, no other code change is needed.
implementation "org.springdoc:springdoc-openapi-ui:1.6.12"
springboot 2.7.0
java 17
#OpenAPIDefinition
public class MyApplication
Swagger URL : http://localhost:8080/swagger-ui/index.html#/

Recently we have upgraded to Java 17, We have added 'org.springdoc:springdoc-openapi-ui:1.6.12' dependency as no other old swagger related dependency were working and Swagger Configuration class looks simple for us now
#Configuration
public class SwaggerConfiguration{
#Bean
public GroupedOpenApi publicApi(){
GroupedOpenApi.builder().group("springshop-publish").pathsToMatch("/**").build();
}
}

Related

Can't open OpenApi (Swagger) page

Gradle:
implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.13'
implementation group: 'io.swagger.core.v3', name: 'swagger-annotations', version: '2.2.7'
Properties:
springdoc.swagger-ui.enabled=true
springdoc.swagger-ui.path=/swagger-ui.html
Controller:
#RestController
#RequestMapping("/api/v1/cheque")
#FieldDefaults(level = AccessLevel.PRIVATE,makeFinal = true)
public class ChequeController {
ProductService productService;
public ChequeController(ProductService productService) {
this.productService = productService;
}
#GetMapping(value = "/get/{id}", produces = "application/json")
public Optional<Product> getByid(#PathVariable Long id) {
return productService.getById(id);
}
#GetMapping("/test")
public String test() {
return "test";
}
}
Conf:
#Configuration
public class OpenApiConfiguration {
#Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(
new Info()
.title("Example Swagger Api")
.version("1.0.0")
);
}
}
Trying to open in localhost:8080/swagger-ui.html and getting:
Whitelabel Error Page There was an unexpected error (type=Not Found, status=404). in https://springdoc.org/#getting-started saying, that it will automatically deploy swagger-ui to a spring-boot application
what im doing wrong
For swagger v3+, the swagger ui default access is now swagger-ui/ instead of swagger-ui.html
You should be able to access by amending your url to localhost:8080/swagger-ui/

Spring returns 404 when using MethodValidationPostProcessor

I have a problem with my test Spring Boot app. It works just fine, but when I enable Spring validation by adding dependency etc and adding a #Configuration:
#Configuration
public class TestConfiguration {
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
I get 404 for my test endpoint.
{
"timestamp": 1601507037178,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/test"
}
I've already applied some solutions/proposals from similar problems (eg here or here) but without a success.
Here is my code:
https://github.com/zolv/error-handling-test
API interface:
#Validated
public interface TestApi {
#PostMapping(
value = "/test",
produces = {"application/json"},
consumes = {"application/json"})
#ResponseBody
ResponseEntity<TestEntity> getTest(#Valid #RequestBody(required = false) TestEntity request);
}
TestEntity just to send something:
#Data
public class TestEntity {
#JsonProperty("test")
#NotNull
private String test;
}
Controller implementation:
#RestController
#RequiredArgsConstructor
#Validated
public class TestController implements TestApi {
#Override
#ResponseBody
public ResponseEntity<TestEntity> getTest(#Valid #RequestBody TestEntity request) {
return ResponseEntity.ok(request);
}
}
My controller advice:
#ControllerAdvice
public class DefaultErrorHandlerAdvice extends ResponseEntityExceptionHandler {
#ExceptionHandler(value = {ConstraintViolationException.class})
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
#ResponseBody
public ResponseEntity<String> handleValidationFailure(ConstraintViolationException ex) {
StringBuilder messages = new StringBuilder();
for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
messages.append(violation.getMessage());
}
return ResponseEntity.badRequest().body(messages.toString());
}
#Override
#ResponseBody
#ResponseStatus(HttpStatus.BAD_REQUEST)
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex,
HttpHeaders headers,
HttpStatus status,
WebRequest request) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.contentType(MediaType.APPLICATION_PROBLEM_JSON)
.body("problem");
}
}
Application:
#SpringBootApplication
#EnableWebMvc
#ComponentScan(basePackages = "com.test")
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
A test I use, but it fails also using Postman:
#SpringJUnitConfig
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class TestControllerTest {
#Autowired protected TestRestTemplate restTemplate;
#Test
void registrationHappyPath() throws Exception {
/*
* Given
*/
final TestEntity request = new TestEntity();
/*
* When/
*/
final ResponseEntity<String> response =
restTemplate.postForEntity("/test", request, String.class);
/*
* Then
*/
Assertions.assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
final String body = response.getBody();
Assertions.assertNotNull(body);
}
}
If I comment out a TestConfiguration then everything works fine.
Thank You in advance for any help.
You should set MethodValidationPostProcessor#setProxyTargetClass(true) because by default MethodValidationPostProcessor uses JDK proxy which leads to loss of your controller in the Spring context.
When AbstractHandlerMethodMapping#processCandidateBean is called isHandler(Class<?> beanType) will return false because JDK proxy doesn't contain #RestController annotation.
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor mvProcessor = new MethodValidationPostProcessor();
mvProcessor.setProxyTargetClass(true);
return mvProcessor;
}

Open API 3.0 using openapi-generator-maven-plugin not showing any swagger doc

Facing this issue with Open API 3.0, I am generating the code using openapi-generator-maven-plugin. I am able to generate the code as well. Code is there in the finally generated Jar of Spring boot as well. But Some how I am not able to see the swagger-doc. All I see is this pop-up with this description
Unable to infer base url. This is common when using dynamic servlet registration or when the API is behind an API Gateway. The base url is the root of where all the swagger resources are served. For e.g. if the api is available at http://example.org/api/v2/api-docs then the base url is http://example.org/api/. Please enter the location manually:
I tried setting up the baseUrl property, like this
baseUrl=http://localhost:8080/api
This isn't working, generated Config & controller has following code.
#Controller
public class HomeController {
#RequestMapping("/")
public String index() {
return "redirect:swagger-ui.html";
}
}
Following is configuration class.
#Configuration
#EnableSwagger2
public class OpenAPIDocumentationConfig {
ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("School REST API")
.description("School REST API")
.license("ABC")
.licenseUrl("http://localhost:8080")
.termsOfServiceUrl("")
.version("1.0.0")
.contact(new Contact("","", "xyz#abc.com"))
.build();
}
#Bean
public Docket customImplementation(ServletContext servletContext, #Value("${openapi.schoolRest.base-path:}") String basePath) {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.school.rest.generated.controllers"))
.build()
.pathProvider(new BasePathAwareRelativePathProvider(servletContext, basePath))
.directModelSubstitute(java.time.LocalDate.class, java.sql.Date.class)
.directModelSubstitute(java.time.OffsetDateTime.class, java.util.Date.class)
.genericModelSubstitutes(Optional.class)
.apiInfo(apiInfo());
}
class BasePathAwareRelativePathProvider extends RelativePathProvider {
private String basePath;
public BasePathAwareRelativePathProvider(ServletContext servletContext, String basePath) {
super(servletContext);
this.basePath = basePath;
}
#Override
protected String applicationPath() {
return Paths.removeAdjacentForwardSlashes(UriComponentsBuilder.fromPath(super.applicationPath()).path(basePath).build().toString());
}
#Override
public String getOperationPath(String operationPath) {
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromPath("/");
return Paths.removeAdjacentForwardSlashes(
uriComponentsBuilder.path(operationPath.replaceFirst("^" + basePath, "")).build().toString());
}
}
}
I have also removed the springfox & swagger related jars from my project.
Please advice.

Add created date time to a REST API using Swagger

I have a couple of APIs and using springfox-swagger for API documentation.
I have a requirement to add the creation date to the respective API. How can I achieve this using swagger. I don't need any API versioning.
Ex:
#ApiOperation(value = "Creates a new user and returns the created user.")
#PostMapping(/user)
public ResponseEntity<UserDto> createUser(#RequestBody UserDto userDto) {
User user =userService.create(userDto);
return new ResponseEntity<>(UserMappers.USER_ENTITY_TO_DTO.apply(user),HttpStatus.CREATED);
}
In the above example, I want to add the creation date of /user so that I can trace the creation date.
In my project I have a similar requirement. As a solution I have created a custom annotation (for marking the endpoint) and wrote a plugin (for updating the API description).
Option #1
#ApiSince annotation:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface ApiSince {
String value() default "";
}
ApiSincePlugin plugin:
#Component
public class ApiSincePlugin implements OperationBuilderPlugin {
private final DescriptionResolver resolver;
#Autowired
public ApiSincePlugin(DescriptionResolver resolver) {
this.resolver = resolver;
}
#Override
public void apply(OperationContext context) {
final String sinceTemplate = "### Since %s%n%n%s";
String notes = "";
Optional<ApiOperation> apiOperationOptional = context.findAnnotation(ApiOperation.class);
if (apiOperationOptional.isPresent()) {
notes = apiOperationOptional.get().notes();
}
String finalNotes = notes;
Optional<ApiSince> apiSinceOptional = context.findAnnotation(ApiSince.class);
if (apiSinceOptional.isPresent()) {
finalNotes = String.format(sinceTemplate, apiSinceOptional.get().value(), notes);
}
context.operationBuilder().notes(resolver.resolve(finalNotes));
}
#Override
public boolean supports(DocumentationType type) {
return true;
}
}
#ApiSince in action:
#ApiSince(value = "2019-10-31")
#PostMapping(value = "/login")
#ApiOperation(value = "Authenticate user", nickname = "login", notes = "your API description")
#ResponseStatus(HttpStatus.OK)
#ApiResponses(value = {
#ApiResponse(code = 200, response = LoginResponse.class, message = HTTP_200_OK),
...
})
#ResponseBody
ResponseEntity<LoginResponse> login(...);
If you don't want do add it in the description but as an extra JSON attribute then take a look at this solution: Custom Operation Builder Plugin
.
Option #2
#ApiSince annotation (code same as above)
ApiSincePlugin plugin:
#Component
public class ApiSincePlugin implements OperationBuilderPlugin {
#Override
public void apply(OperationContext context) {
Optional<ApiSince> annotation = context.findAnnotation(ApiSince.class);
if (annotation.isPresent()) {
String value = annotation.get().value();
ObjectVendorExtension extention = new ObjectVendorExtension("x-since");
extention.addProperty(new StringVendorExtension("value", value));
context.operationBuilder().extensions(Collections.singletonList(extention));
}
}
#Override
public boolean supports(DocumentationType documentationType) {
return true;
}
}
Activate extensions in the Swagger UI:
#Bean
UiConfiguration uiConfig() {
return UiConfigurationBuilder
.builder()
.showExtensions(true)
...
.build();
}
#ApiSince in action (code same as above):

Swagger ui returns Whitelabel Error

I used swagger 2.9.2 in my spring boot app.
localhost:8080/api-docs works fine.
However, localhost:8080/swagger-ui.html returns writelabel error.
localhost:8080/v2/swagger-ui.html and localhost:8080/api/swagger-ui.html return the same error.
I must have missed something simple. Thanks.
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Wed Aug 22 10:05:48 CDT 2018
There was an unexpected error (type=Not Found, status=404).
No message available
In build.gradle, I have dependency of springfox.
compile("io.springfox:springfox-swagger2:2.9.2")
compile("io.springfox:springfox-swagger-ui:2.9.2")
swaggerconfig.java
#Configuration
#EnableSwagger2
public class SwaggerConfig{
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage(MyServiceController.class.getPackage().getName()))
//.apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
.paths(PathSelectors.ant("/api/**"))
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
String description = "Company - My API";
return new ApiInfoBuilder()
.title("REST API")
.description(description)
.version("1.0")
.build();
}
MyServiceController.java
#ApiOperation(value = "some description",
response = MyServiceResponse.class)
#ApiResponses(value = {
#ApiResponse(code = 200, message = "ok"),
#ApiResponse(code = 400, message = "Bad Request"),
#ApiResponse(code = 401, message = "not authorized"),
#ApiResponse(code = 403, message = "not authenticated"),
#ApiResponse(code = 404, message = "The resource you were trying to reach is not found"),
#ApiResponse(code=500, message = "Interval Server Error")
})
#RequestMapping(method = RequestMethod.POST, value = "/api/component/operation", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE)
#ResponseBody
{
do something
}
Hey I am using Spring boot 2.1.4, Swagger 2.9.2, I faced the same issue and got resolved by the following:
It seems that you have the required dependencies so this is not the issue.
I think the issue that you have to implement WebMvcConfigure and override addResourceHandlers method:
#Configuration
#EnableSwagger2
public class SwaggerConfig implements WebMvcConfigurer {
// your Docket and ApiInfo methods
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
Just try to add it and Share what happen with you.
Return the Docket bean like below :
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
}
and add #RestController annotation above your controller class
So if u have correctly written the swaggerConfig code also added the right dependencies and still getting error
The ultimate solution is
You need to have perfect combination of swagger version and spring boot version
Just change the spring boot and swagger version as below
Check in your pom.xml or gradle build
Spring boot version :- <version>1.4.1.RELEASE</version>
Swagger and Sawgger ur version:- <version>2.2.2</version>
There are other combinations available but that u need to try on trial basis
I have the same problem, and solve with this Docket bean config:
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(Predicates.not(PathSelectors.regex("/error.*")))
.build()
.apiInfo(this.apiInfo());
}
it works for me.
I faced the same issue and got resolved by the following
You can use one dependency:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
SwaggerConfig class like below :
#Configuration
#EnableSwagger2
public class SwaggerConfig implements WebMvcConfigurer {
#Bean
public Docket api(){
return new Docket(DocumentationType.SWAGGER_2);
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
do not use #EnableSwagger2 3.0 version
http://localhost:8080/swagger-ui/index.html

Categories