This is the continuation of my earlier posting, Swagger For the REST of Us. Here, I will cover Springfox integration with my REST Hello World project. Though Springfox supports both 1.2 and 2.0 versions of the Swagger specification, I will stick to Swagger 2.0 specification.
Swagger generates metadata including server host name, endpoint URL, mime-types that the API can consume or produce, data types produced and consumed by operations, etc. Swagger exposes API documentation in JSON format by scanning the source code. Swagger UI is part of the Swagger project and consists of a collection of HTML, Javascript, and CSS resources. Swagger UI takes Swagger compliant JSON API documents as input and dynamically generates an interactive UI of the REST services.
I will continue with the ongoing REST Hello World example. You can find the last version of the example in REST API and Error Handling posting. The example source code mentioned in this posting can be found here.
Changes to Maven Dependencies
- Add springfox-swagger2 dependency to integrate Swagger Springfox with Spring REST service example.
- Add springfox-swagger-ui dependency to enable Swagger UI.
<!-- Swagger Spring --> | |
<dependency> | |
<groupId>io.springfox</groupId> | |
<artifactId>springfox-swagger2</artifactId> | |
<version>2.4.0</version> | |
</dependency> | |
<!-- Swagger UI --> | |
<dependency> | |
<groupId>io.springfox</groupId> | |
<artifactId>springfox-swagger-ui</artifactId> | |
<version>2.4.0</version> | |
</dependency> |
Configure Docket Configuration Bean
Create a new Docket bean to configure Swagger. A Docket bean is a POJO enabled by @Configuration, @EnableSwagger2, and @Bean annotations. For Swagger 2.0, use @EnableSwagger2 annotation. Here is the example Docket bean:
@Configuration | |
@EnableSwagger2 | |
public class SwaggerConfiguration { | |
@Bean | |
public Docket api() { | |
return new Docket(DocumentationType.SWAGGER_2).select().apis( | |
RequestHandlerSelectors.any()).paths(PathSelectors.any()).build(); | |
} | |
} |
Import the bean by adding the package name (if it’s missing) in the component-scan tag of the existing rest-dispatcher-servlet.xml.
<context:component-scan base-package= | |
"basaki;basaki.service;basaki.service.controller; | |
basaki.service.impl;basaki.data" /> |
Verification of Swagger
Once you have the example running, Swagger documentation in JSON format can be viewed at localhost:8080/rest-swag-simple/api-docs.
Enable Swagger UI
Other than the addition of new springfox-swagger-ui dependency in the pom.xml, changes need to be made to the rest-dispatcher-servlet.xml to serve the static UI content of Swagger UI. Here are the changes to rest-dispatcher-servlet.xml:
<!-- Direct static mappings --> | |
<mvc:resources mapping="swagger-ui.html" | |
location="classpath:/META-INF/resources/" /> | |
<mvc:resources mapping="/webjars/**" | |
location="classpath:/META-INF/resources/webjars/" /> |
Verification of Swagger UI
Once you deploy the example in Tomcat, the Swagger UI can be viewed by visiting http://localhost:8080/rest-springfox/swagger-ui.html in any browser. In my experience, the behavior of Swagger in Internet Explorer is flaky.
Once you have access to Swagger UI, you can view all the operations by clicking Show/Hide.
You can play around with any of the operations by clicking the operation link. Once the operation is expanded, you can retrieve data by clicking Try it out! button. In this example, try out getCustomers operation. It should fetch a list of customers.
Further Customization of Controller (Optional)
Use Swagger annotation to make the API more descriptive and hide some of the internal information, e.g., a controller’s method names, etc. Here are some of the Swagger annotations commonly used to document a controller:
- @Api describes the general responsibility of the controller.
- @ApiOperation describes the responsibility of a specific method.
- @ApiParam describes a method parameter. It also describes whether a parameter is mandatory or not.
@Controller | |
@Api(value = "customers") | |
public class CustomerServiceController { | |
... | |
@ApiOperation(value = "Gets a customer based on customer id", | |
notes = "Retrieves a single customer", response = Customer.class) | |
@RequestMapping(method = RequestMethod.GET, | |
produces = { MediaType.APPLICATION_XML_VALUE, | |
MediaType.APPLICATION_JSON_VALUE }, | |
value = "customers/{id}") | |
@ResponseBody | |
public Customer getCustomer(@PathVariable Integer id) { | |
Customer customer = service.getCustomer(id); | |
return customer; | |
} | |
... | |
} |
Swagger UI should look more descriptive if you now visit http://localhost:8080/rest-springfox/swagger-ui.html in your browser.
this post saved my day
LikeLike
Hi,
I tried following your guide and I am stuck with the following problem whenever I try to go to the /swagger-ui.html page
Can’t read swagger JSON from http://localhost:8080/services.appundefined
Any thoughts on the cause of this?
The call to http://localhost:8080/services.app/v2/api-docs.json is working fine.
Thanks for this great post and your time.
LikeLike
Which version of springfox you are using? Can you download my project (linked provided above) and try it out.
LikeLike
I tried your repo https://github.com/indrabasak/rest-springfox but i am getting 404 when i try to access http://localhost:8080/rest-springfox/v2/api-docs.json and
http://localhost:8080/rest-springfox/swagger-ui.html
LikeLike
I just tried in Tomcat 8.0, it worked fine for me. Which web container are you deploying? Can you access the url, http://localhost:8080/rest-springfox/
LikeLike
Can you add description of the end point in Swagger UI.
LikeLike
Yes, you can. To add description of endpoints, you need to use @Api and @@ApiOperation annotations. Please check my class CustomerServiceController.java.
LikeLike
Hi, I’m using Tomcat 7 and I get 404 on hitting URL
http://localhost:8080//api-docs.json
can you please help
LikeLike
If you are using my example, the correct URL for Swagger UI:
http://localhost:8080/rest-springfox/swagger-ui.html
For swagger JSON:
http://localhost:8080/rest-springfox/v2/api-docs
LikeLike
http://localhost:8080/swagger-ui.html – try this
LikeLike
Simple example that works. thanks!
LikeLike
Good post. Followed step by step and its working, but the problem is that i am not able to change the request URL in the swagger ui .it’s always pointing to the localhost:8080. I have hosted it in the server which has public IP. so finally it should fetch the public ip but it is fetching the localhost ip which makes it difficult to check the services. Help needed.
LikeLike
Please post the screenshot error you are seeing
LikeLike
Please click on this url
https://swagger500.wordpress.com/2017/04/15/issue-i-am-getting-when-i-deploy-the-swagger-in-the-puplic-ip/
LikeLike
Please click on the below url
https://swagger500.wordpress.com/2017/04/15/issue-i-am-getting-when-i-deploy-the-swagger-in-the-puplic-ip/
LikeLike
Can you please try the latest version of springfox – 2.6.1? I don’t see any problem with one of my other deployments which has a different host name than localhost.
LikeLike
I am trying with the latest version of the springfox.
LikeLike
It’s kind of a hack but try this.
LikeLike
It worked but how can we get the host name dynamically ??
LikeLike
I want know how can we hide the Controller name ex (custom-service-controller) to (Custom Controller). Is there any annotation to rename that. @Api with value and description but it did not reflect).
LikeLike
When you type ‘hostname’ on your computer terminal, what do you get in return? If it’s ‘localhost’, you need to modify your DNS. How to modify, depends on your OS.
LikeLike
Thanks for the reply. How can i hide the fully qualified name of the controller and give a different name to that.
LikeLike
You need to change the value in ‘tags’ parameter in @Api annotation. Here is an example:
@Api(value = "Customers API",
description = "Customer Service",
produces = "application/json", tags = {"Customer Controller"})
It should appear in the UI as:
Api Documentation
Api Documentation
Apache 2.0
LikeLiked by 1 person
Description in the @Api is deprecated. Is there any way overcome this.
LikeLike
Though it’s deprecated, it still works. There is no alternative.
LikeLike
I have service which takes a requestbody of some model class ex(Users). In this model class i have like 10 attributes. Fo the service i am using only 4 attributes. How can i show only the 4 attributes in swagger UI example value for that service.
class Users{
private String userName;
private String password;
private String firstName;
private String lastName;
private String middleName;
private String address;
private String gender;
private String dob;
}
Swagger Ui Exampl Value
{
“firstName”: “string”,
“middleName”: “string”,
“lastName”: “string”
}
LikeLike
You can take advantage of the
hidden
parameter in@ApiModelProperty
annotation. Here is an example:Swagger Ui model should appear like this:
LikeLike
Thanks for the reply.
If the same model class is input for two services and these two require different attributes of the same class
/getUser accepts json (users object as requestbody)
{
“firstName”: “string”,
“userName”: “string”,
“lastName”: “string”
}
/addUser accepts json (users object as requestbody)
{
“firstName”: “string”,
“middleName”: “string”,
“lastName”: “string”
}
in this scenario how can i display the example value.
LikeLike
You should use different models.
LikeLike
How can i sort the services by HttPMethod ??
LikeLike
You can’t. ‘position’ attribute is deprecated and doesn’t work anymore.
LikeLike
Thank you very much. Really saved a lot of time.
LikeLike
I want to remove controller information how can I do it
LikeLike
Please see my latest post ‘Revisiting Swagger’.
LikeLike
Getting following exception:
/router/v2/api-docs
java.lang.IllegalArgumentException: HttpServletRequest must not be null
LikeLike
I need to look at your code before commenting.
LikeLike
Hi,
I have multiple rest API’s in a project, r if every api i need to configure swagger separately . So how to make swagger globally for the project and how i use for every api .
LikeLike
If all your REST controllers are in the same package, only thing you have to do is specify the package during the creation of the Docket. Here is an example of Java configuration:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
MySwaggerConfiguration.java
hosted with ❤ by GitHub
LikeLike
Thanks, will try it..
🙂
LikeLike
Hi,
So if my project have different modules and the RestControllers are placed in different packages, so is there any way scan multiple packages ..for ex : apis(exactPackage(“com.basaki.example.controller”). here we are scan only one package level insted of this want to scan multiple package from single swagger and make it as global for api documentation.
LikeLike
Please checkout my Swagger Deep dive project in GitHub.
LikeLike
Hi,
it’s working fine. But If I integrate with multiple resources are there in project (when integration time of multiple projects) it won’t scan the other resources packages. why because exactPackage() method fetching classes packages from only one resource. Could you please tell me how to scan project specified path level with single swagger configuration.
LikeLike
it’s working fine. But If I integrate with multiple resources are there in project (when integration time of multiple resources are in projects) it won’t scan the other resources packages. why because exactPackage() method fetching classes packages from only one resource. Could you please tell me how to scan project specified path level with single swagger configuration.
LikeLike
You can do something like this.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
MultiPackageSwaggerConfig.java
hosted with ❤ by GitHub
LikeLike
is there a way to have a single consolidated UI for different spring boot modules? For ex. i have a Parent project which has like 5 microservices, i want to have a single context where i can show all the apis in a single place.
LikeLike
Yes, it’s very simple. Just create a Swagger configuration specifying all the controllers. The controller may reside in different modules. In this example, it list all the controllers marked with annotation Api.class.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
MultiModuleSwaggerConfiguration.java
hosted with ❤ by GitHub
LikeLike
hey there..good article..could you show an example when the request body or the response body are of Map type using springfox 2.7
LikeLike
It shouldn’t be any different from other service methods. Please pay attention to method ‘readMap’ in the ‘TigerController’ example:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
TigerController.java
hosted with ❤ by GitHub
Used springfox 2.7.0 version. Here is the response body.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
JsonMapResponse
hosted with ❤ by GitHub
LikeLike
Hi Indra, mostly i have followed this example. but i am using LUIS server. and I am getting below error. please share if you have any info on this. thank you.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping’: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Cannot convert value [com.lloydstsb.luis.jndi.JNDIContext@171e98f {}] from source type [JNDIContext] to target type [String]
LikeLike
It’s something to do with your @RequestMapping annotation in your controller. It can’t convert of the type your are passing ‘com.lloydstsb.luis.jndi.JNDIContext’ to String. Please post your Controller mapping before I comment any further.
LikeLike
Excellent resource…If you follow the steps carefully everything works…thanks a lot
LikeLike
Hi,
Am using spring boot REST API, my controller has GET request00:00:00.0000000″. Soam passing path variable”2017-09-08 00:00:00.0000000″ with url. But once the value coming into controller side as a string the it shows only “2017-09-08 00:00:00”, after dot(.) the reaming value as trim and has getting only “2017-09-08 00:00:00”. please suggest me why it happen.
LikeLike
Please post your controller code.
LikeLike
@RequestMapping(value =”/fetchRecipeMetadataByKeyValue/{keyFilter}/{keyValue}” ,method = RequestMethod.GET , produces = “application/json”)
public String fetchRecipeMetadataByKeyValue(@PathVariable String keyFilter,@PathVariable String keyValue){
JSONObject metadata = new JSONObject();
List recipeMetadataList = new ArrayList();
metadataList = metadataService.getMetaDataByKey(filterKey, keyValue);
metadata.put(“MetaData”, metadataList);
From Swagger Side:–>
keyFilter = modified_date (data type = string)
keyValue = 2017-08-31 00:00:00.0000000 (data type =string)
LikeLike
when debugging controller side – keyValue = has shown 2017-08-31 00:00:00 only. what is the problem here
LikeLike
The problem is not with Swagger but with Message Converter. Have you tried calling the endpoint from a browser or Postman and check what the behavior is?
LikeLike