I have developed a RESTful web service in Java and Spring boot using Jax-RS and I would like to document it with Swagger. I have so far successfully managed to map the swagger-ui.html page on http:8080/localhost/<context>/swagger-ui.html. Unfortunately, my RESTful endpoints do not appear anywhere.
What I am using:
pom.xml
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
Swagger configuration class
#Configuration
#EnableSwagger2
public class SwaggerConfiguration
{
#Autowired
private TypeResolver typeResolver;
#Bean
public Docket api()
{
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("org.nick.java.webservice.services"))
.paths(PathSelectors.any())
.build()
.enable(true)
.apiInfo(getApiInfo())
.tags(
new Tag("My web service", "Methods for my RESTful service")
);
}
private ApiInfo getApiInfo() {
ApiInfo apiInfo = new ApiInfoBuilder()
.title("API Documentation")
.description("API")
.version("1.0")
.contact(new Contact("mycompany", "", "nickath#mycompany.com"))
.build();
return apiInfo;
}
an example of the JAX-RS endpoints
package org.nick.java.webservice.services;
#Path("/contextsapi")
#Consumes("application/json")
#Produces("application/json")
#Api(value = "Contexts API", produces = "application/json")
public interface ContextAPI {
#Path("/contexts/contexts")
#GET
#ApiOperation( value = "get contexts",
response = List.class)
List<Context> getContexts();
screenshot of the swagger-ui.html page
as you can see, no 'get contexts' method has been generated
Any idea what I am doing wrong?
======= UPDATE - SERVICE IMPLEMENTATION ========
package org.nick.java.webservice.services.impl;
#Service
#Api(value = "Contexts Api Impl", produces = "application/json", description = "desc")
#Path("/contextsapi")
public class ContextAPIImpl implements ContextAPI {
#Override
#GET
#ApiOperation( value = "get contexts", response = List.class)
public List<Context> getContexts(){
//code ommitted
}
}
Solved
Finally I managed to solve my problem using the Swagger2Feature following the example from here https://code.massoudafrashteh.com/spring-boot-cxf-jaxrs-hibernate-maven-swagger-ui/
Maven dependencies
<cxf.version>3.1.15</cxf.version>
<swagger-ui.version>3.9.2</swagger-ui.version>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxrs</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-service-description-swagger</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>swagger-ui</artifactId>
<version>${swagger-ui.version}</version>
</dependency>
CxfConfig.java
#Configuration
public class CxfConfig {
#Autowired
private Bus bus;
#Bean
public Server rxServer(){
final JAXRSServerFactoryBean endpoint = new JAXRSServerFactoryBean();
endpoint.setProvider(new JacksonJsonProvider());
endpoint.setBus(bus);
endpoint.setAddress("/swagger");
endpoint.setServiceBeans(Arrays.<Object>asList(contextAPI());
Swagger2Feature swagger2Feature = new Swagger2Feature();
endpoint.setFeatures(Arrays.asList(swagger2Feature));
return endpoint.create();
}
#Bean
public ContextAPI contextAPI(){
return new ContextAPIImpl();
}
Now the swagger documentation is available on http://localhost:8080///swagger/api-docs?url=//swagger/swagger.json
To customize the endpoint's UI check the manual here
Swagger suppose not to show documentation for any API client. It will generate documentation for your service if there is any with swagger annotations.
To be confirmed about this, try creating a Spring #service and annotate with swagger annotations. The doc will be generated if every other aspects are taken care of. Since you can see the UI, I would assume the dependencies are right.
The idea here is, your task is to document your service and swagger helps with that. It's not your responsibility to generate/publish documentation for API(s) that your service consumes. Since you don't maintain the service, it doesn't make sense to maintain the documentation as well.
When I used Rest client for the first time, I also got a bit perplexed about this. But if you really think about it, this is expected and makes sense.
I would suggest to use Swagger 2 i faced the same issue.
the issue is with the Docket you have implemented , correct regular expression can help.
Example :
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
}
You can refer to the link above Setting up Swagger 2 Example
The Source code example is also from the above link.
Related
I have a problem with swagger documentation using SpringBoot with Springfox-boot-starter.
I use java.time.Instant wrapped in java.util.Optional in my REST API which works fine:
#GetMapping("/{subscriptionId}/{variableAlias}")
public PaginatedResultDTO<MonitoredVariableDTO> getReportedVariables(
#PathVariable String subscriptionId,
#PathVariable String variableAlias,
Optional<Instant> from,
Optional<Instant> to) { ... }
But for some reason, Swagger documentation cannot handle the Optional type correctly and seems to handle it through reflection as EpochSeconds and Nano attributes instead of one field:
I would like to make swagger expect from and to instants in ISO format, just like Spring does and how I use it in Insomnia:
When I tried to remove the Optional wrapper, it seems to work
Is there a way to make this work with the Optional? Thanks for any advice!
Spring boot version:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath />
</parent>
Springfox-boot-starter version
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
We had exactly the same problem that you.
We solved it with this SpringFox configuration:
#Configuration
#EnableSwagger2
public class SpringfoxConfiguration {
#Value("${api-doc.version}")
private String apiInfoVersion;
#Autowired
private TypeResolver typeResolver;
#Bean
public Docket customDocket(){
return new Docket(DocumentationType.SWAGGER_2)
.groupName("xxx")
//Some other code unrelated to this problem
.alternateTypeRules(
// Rule to correctly process Optional<Instant> variables
// and generate "type: string, format: date-time", as for Instant variables,
// instead of "$ref" : "#/definitions/Instant"
AlternateTypeRules.newRule(
typeResolver.resolve(Optional.class, Instant.class),
typeResolver.resolve(Date.class),
Ordered.HIGHEST_PRECEDENCE
))
.genericModelSubstitutes(Optional.class)
.select()
//Some more code unrelated to this problem
.build();
}
}
With spring fox the problem is it doesn't use the custom ObjectMapper which you have defined as a Bean.
Springfox creates own ObjectMapper using new keyword. Hence, any module you register with your custom ObjectMapper is pointless for SpringFox. However, Springfox provides an interface to register modules with it's own ObjectMapper.
Create a configuration bean like below in your project and it should work.
#Configuration
public class ObjectMapperModuleRegistrar implements JacksonModuleRegistrar {
#Override
public void maybeRegisterModule(ObjectMapper objectMapper) {
objectMapper.registerModule(new ParameterNamesModule())
.registerModule(new Jdk8Module())
.registerModule(new JavaTimeModule())
.findAndRegisterModules();
}
}
For some reason bootstrap webjars are not being copied into target, and for that reason they cannot be found.
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
</parent>
...
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>4.1.3</version>
</dependency>
Resource handlers:
#Configuration
#EnableWebMvc
public class WebConfiguration implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/WEB-INF/resources/*");
registry.addResourceHandler("/resources/").addResourceLocations("/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
Somewhere in my static resources
...
<script src="webjars/bootstrap/4.1.3/js/bootstrap.min.js"></script>
...
Nothing is generated into /target
Any idea what am I missing?
I spend few hours on this and also reached second page on google searches.
I will answer my own question.
I would never tell that could be a problem but apparently #GetMapping annotation broke my UI. I still didn't figure it out what was the problem. I just found solution.
So I used Thymeleaf to resolve my views
#Controller
public class ViewController {
#GetMapping("/")
public String home() {
return "/home";
}
}
And apparently it clashes when I use traditional Restful controller
#RestController(value = "/face-detection")
public class FaceDetectController {
#GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) {
...
This single #GetMapping was breaking entire UI.
What I had to do was simply add / in the mapping
#GetMapping(value ="/", produces = MediaType.APPLICATION_JSON_VALUE)
And the whole thing magically started to work.
Similar issue somewhere deep in the github:
https://github.com/springfox/springfox/issues/1647
I want to use Swagger 2.0 with my Spring Boot RESTful web service to generate documentation. I have searched quite a bit for an answer to this. Basically I have a Spring Boot project with a set of controllers and I want to document the API's. I have the following dependencies setup in my POM file.
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.5.0</version>
</dependency>
This is my Swagger configuration class with the #Configuration and #EnableSwagger2:
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket api(){
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.regex("/api/.*"))
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("My application title")
.description("This is a test of documenting EST API's")
.version("V1.2")
.termsOfServiceUrl("http://terms-of-services.url")
.license("LICENSE")
.licenseUrl("http://url-to-license.com")
.build();
}
}
From what I have gathered in reading a couple of other answers here that at this point I should be able to see something at a URL such as http://myapp/v2/api-docs or alternatively http://localhost:8080/myapp/api-docs I have made the assumption that the "myapp" portion of the above URL refers to the name of the class in which my main resides (is this correct)? Also I have tried this with port 8080 and port 80 and the bottom line is that I see nothing other than site can't be reached. I have looked at the answers provided here and here however I'm not having any success. Any help would be much appreciated, thank you in advance.
As you can see on the following documentation :
https://springfox.github.io/springfox/docs/snapshot/#springfox-swagger-ui
The endpoint is now on swagger-ui.html, for your case, it will be http://localhost:8080/myapp/swagger-ui.html
I used, <artifactId>springdoc-openapi-ui</artifactId> with
public class OpenApiConfiguration{
#Bean
public GroupedOpenApi abcApp(){
String[] abcAppRootPath={"com.stockoverflow.swagger"};
return GroupedOpenApi.builder().group("my app").packagesToScan(abcAppRootPath).build();
}
}
reference : https://springdoc.org/#getting-started
I am building a REST API. Its made up of a Resource ( #Controller ) which returns a response 204 even when one of the mandatory field is not present.
I am using Spring 3.1, validation-api (1.1.0.Final) & Hibernate-validator(4.3.0). Not sure if Hibernate-validator plays any role here.
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.3.0.Final</version>
<exclusions>
<exclusion>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</exclusion>
</exclusions>
</dependency>
I have a spring controller #Controller and a Bean with #Component
#POST
#Consumes(value = {MediaType.APPLICATION_JSON})
#Produces(value = {MediaType.APPLICATION_JSON})
#RequestMapping(method = RequestMethod.POST)
public Response addUserData(#Valid #RequestBody UserData userDataRequest) throws ResourceException {
...
}
My UserData bean has
#Component
public class UserData {
#NotNull(message = "user ID should not be null")
#Min(value = 1, message = "user ID should not be empty")
#Max(value = 20, message = "user ID should have length of more than 20")
#Pattern(regexp="[A-Z][a-z]+", message = "Only Alphanumeric characters allowed")
private String userId;
}
My validations are not getting executed. When I dont pass "userId", there is no error thrown. What am I missing here ?
You must have the following about the infrastructure
#EnableWebMvc
#Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
...
#Autowired
private ValidatorConfig validatorConfig;
...
#Override
public Validator getValidator() {
return validatorConfig.localValidatorFactoryBean();
}
...
}
Where validatorConfig comes from
#Configuration
public class ValidatorConfig {
#Autowired
private ReloadableResourceBundleMessageSource rrbms;
#Bean
public LocalValidatorFactoryBean localValidatorFactoryBean(){
LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
localValidatorFactoryBean.setValidationMessageSource(rrbms);
return localValidatorFactoryBean;
}
}
And finally (I suggest you consider put the error messages in a .properties file, such as validation.properties how shown below)
#Configuration
public class MessageSourceConfig {
#Bean(name="messageSource")
public ReloadableResourceBundleMessageSource reloadableResourceBundleMessageSource() {
ReloadableResourceBundleMessageSource resource = new ReloadableResourceBundleMessageSource();
resource.setBasenames("classpath:/com/manuel/jordan/somethinga",
"classpath:/com/manuel/jordan/validation/validation");
resource.setDefaultEncoding("UTF-8");
return resource;
}
}
Some considerations or suggestions:
change #Valid to #Validated (see the API for the #Validated)
Remove the #Component for UserData (that represents a kind of entity right?). Remember that for that class each instance is unique and any bean managed by Spring is Singleton.
put the error messages in a .properties file
from where come the #POST, #Consumes and #Produces annotations?. They are not in the Spring API
Addition 01 about your comment:
Yes, you must use #EnableWebMVC. It indicates to Spring create some special beans internally for the web environment. See the #EnableWebMVC API. Is very important that annotation. Even for Rest I use that annotation.
About the Rest annotations, use the Spring annotations. Such as #RequestMapping and new 'variations' such as #GetMapping, #PostMapping etc.. That annotations contain the produces and consumes attributes. I have never seen your approach about mixing two sets of annotations from Rest.
Addition 02
The WebMvcConfigurerAdapter class represents the XML configuration file about all the Spring MVC infrastructure
Therefore for XML
#EnableWebMvc is equivalent <mvc:annotation-driven/>
About validation it should be: <mvc:annotation-driven validator="beanNameValidator" /> where the validator attribute according with the .xsd says:
Attribute : validator The bean name of the Validator that is to be
used to validate Controller model objects. This attribute is not
required, and only needs to be specified explicitly if a custom
Validator needs to be configured. If not specified, JSR-303
validation will be installed if a JSR-303 provider is present on the
classpath.
beanNameValidator according with my #Bean seems should be localValidatorFactoryBean
I ultimately ended up using Jersey Bean Validation, instead of Spring. This is because rest of my code is using Jersey anyways. To make this work I just imported Jersey Bean Validation jar and added a small change to web.xml. Validations are now working.
Thank you #Manual Jordan. I will upvote your answer, since it gave me the right clues.
<!-- jersey beanValidation -->
<init-param>
<param-name>jersey.config.beanValidation.enableOutputValidationErrorEntity.server</param-name>
<param-value>true</param-value>
</init-param>
Maybe passing to your "addUserData" method, a bindingResult Object, so you can test for and retrieve validation errors.
here is an example of how to use it : Validation form input
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 5 years ago.
Improve this question
I am trying to configure swagger ui in non spring boot app. I have done following things.
1. Added Following dependencies
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.3.5</version>
</dependency>
2. Added Swagger Config class
#Configuration
#EnableSwagger2
#EnableWebMvc
//#PropertySource("classpath:/swagger.properties")
public class SwaggerConfig {
#Bean
public Docket proposalApis(){
return new Docket(DocumentationType.SWAGGER_2)
.groupName("test")
.select()
.apis(RequestHandlerSelectors.basePackage("com.test.abc"))
.paths(PathSelectors.regex("/test1.*"))
.build()
.apiInfo(testApiInfo());
}
private ApiInfo testApiInfo() {
ApiInfo apiInfo = new ApiInfoBuilder().title("Test APIs").description("GET POST PUT methods are supported ").version("V1").build();
return apiInfo;
}
}
Added following mappings :
<mvc:resources mapping="swagger-ui.html" location="classpath:/META- INF/resources/"/>
<mvc:resources mapping="/webjars/**" location="classpath:/META- INF/resources/webjars/"/>
I am able to access following url's
/v2/api-docs
/swagger-resources
But While loading swagger-ui.html UI gets loaded and on server getting following error
No mapping found for /context/swagger-resources/configuration/ui in Dispatcher servlet
Can someone help?
I'm using Swagger version 2.3.1 in my pom. I wonder why you have different versions for springfox-swagger2 and springfox-swagger-ui artifacts?
My SwaggerConfig class looks like this. No properties:
#EnableSwagger2
#Configuration
public class SwaggerConfig {
#Autowired
private TypeResolver typeResolver;
#Bean
public Docket swaggerSpringMvcPlugin() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("FooBar")
.select()
//Ignores controllers annotated with #CustomIgnore
.apis(any()) //Selection by RequestHandler
.paths(paths()) // and by paths
.build()
.apiInfo(apiInfo()
);
}
private ApiInfo apiInfo() {
return new ApiInfo("FooBar",
"A java server based on SpringBoot",
"1.0.0",
null,
"author","","");
}
//Here is an example where we select any api that matches one of these paths
private Predicate<String> paths() {
return or(
regex("/foobar/*.*")
);
}
}
No configuration or resources for me.
The page comes right up when I hit the URL http://localhost:8080/foobar/swagger-ui.html
Different versioning of springfox-swagger2 and springfox-swagger-ui has been an issue. In some cases, like former of 2.5.0 and latter of 2.6.1 version, the integration works fine. But, if former is of 2.6.1 and latter is of 2.4.0, then the ui becomes incompatible. Hence, I suggest if both the dependencies are taken of same version by practice, then unexpected functioning of swagger can be reduced.