As IBM VP Angel Diaz stated in an interview on SearchCloudComputing “Swagger is the way most developers describe [REST] APIs”. With version 2.0 many important features like extensibility have been added, there is a big community and many developers are using it by now. Additionally there is work going on to create an open governance model around the Swagger specification under the Linux Foundation as part of the Open API Initiative.
What I like most about Swagger is the ability to document APIs directly in the (Java) source code via annotations so that documentation and actual API implementations are not out of synch.
IBM uses Swagger for the API documentation of several products and services internally. Furthermore the API management service in IBM Bluemix can import Swagger 2.0 definitions to manage your APIs easily.
The Java Spring framework has a lot of traction in the enterprise community these days. In order to use Swagger in Spring Boot applications I tried Springfox which is not part of Swagger core but it integrates nicely in Spring and supports the core Swagger annotations.
Below I extended the Spring sample Building a RESTful Web Service with Swagger annotations.
First you need to define the dependencies to the Springfox and Swagger libraries, in my case in Maven.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.springframework</groupId> <artifactId>gs-rest-service</artifactId> <version>0.1.0</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.0.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.2.2</version> <scope>compile</scope> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.2.2</version> <scope>compile</scope> </dependency> </dependencies> <properties> <java.version>1.8</java.version> </properties> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-releases</id> <url>https://repo.spring.io/libs-release</url> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>spring-releases</id> <url>https://repo.spring.io/libs-release</url> </pluginRepository> </pluginRepositories> </project>
Then I enabled Swagger in the boot application.
package hello; import static springfox.documentation.builders.PathSelectors.regex; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import com.google.common.base.Predicate; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @SpringBootApplication @EnableSwagger2 @ComponentScan("hello") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean public Docket newsApi() { return new Docket(DocumentationType.SWAGGER_2) .groupName("greetings") .apiInfo(apiInfo()) .select() .paths(regex("/greeting.*")) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("Spring REST Sample with Swagger") .description("Spring REST Sample with Swagger") .termsOfServiceUrl("http://www-03.ibm.com/software/sla/sladb.nsf/sla/bm?Open") .contact("Niklas Heidloff") .license("Apache License Version 2.0") .licenseUrl("https://github.com/IBM-Bluemix/news-aggregator/blob/master/LICENSE") .version("2.0") .build(); } }
In the controller I used Swagger annotations to document the API.
package hello; import java.util.concurrent.atomic.AtomicLong; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; import io.swagger.annotations.ResponseHeader; @RestController public class GreetingController { private static final String template = "Hello, %s!"; private final AtomicLong counter = new AtomicLong(); @ApiOperation(value = "getGreeting", nickname = "getGreeting") @RequestMapping(method = RequestMethod.GET, path="/greeting", produces = "application/json") @ApiImplicitParams({ @ApiImplicitParam(name = "name", value = "User's name", required = false, dataType = "string", paramType = "query", defaultValue="Niklas") }) @ApiResponses(value = { @ApiResponse(code = 200, message = "Success", response = Greeting.class), @ApiResponse(code = 401, message = "Unauthorized"), @ApiResponse(code = 403, message = "Forbidden"), @ApiResponse(code = 404, message = "Not Found"), @ApiResponse(code = 500, message = "Failure")}) public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) { return new Greeting(counter.incrementAndGet(), String.format(template, name)); } }
In the sample resource I documented parameters.
package hello; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModelProperty; public class Greeting { private final long id; private final String content; public Greeting(long id, String content) { this.id = id; this.content = content; } public long getId() { return id; } @JsonProperty(required = true) @ApiModelProperty(notes = "The name of the user", required = true) public String getContent() { return content; } }
Here is the outcome in the API explorer.
If you want to run Spring Boot applications in the cloud, check out the IBM Cloud.
Hey, great post.
Have you tried Liberty’s latest December Beta? https://developer.ibm.com/wasdev/blog/2015/11/20/beta-was-liberty-beta-with-tools-december-2015/
The new apiDiscovery-1.0 feature will let Liberty auto-generate a Swagger document from your jaxrs app’s annotations (including Swagger 2.0 annotations). You can then view it through a UI (/ibm/api/explorer), just like StrongLoop and Swagger’s Petstore sample.
Here’s the doc: http://www-01.ibm.com/support/knowledgecenter/was_beta_liberty/com.ibm.websphere.wlp.nd.multiplatform.doc/ae/twlp_api_discovery.html
You could package that server and deploy to Bluemix. Or, you could hook up the API-Management service from Bluemix to your Liberty instance by importing the /ibm/api/docs URL from your Liberty server (it is a valid Swagger 2.0 JSON doc)
– Arthur
Cool. Didn’t know this. Thanks for sharing, Arthur.
/swagger-ui.html is not comings.
Showing like below..
There was an unexpected error (type=Method Not Allowed, status=405).
Request method ‘GET’ not supported
Niklas Heidloff Swagger intrigued me at the beginning as it generated nice looking docs quickly.
However it takes a lot of duplication in the *code*.
E.g. @RequestParam and @ApiImplicitParam containing both the name.
And also the @ApiResponse annotations have to be added each time.
It’s not only that the code is bloated with a lot of annotations, also keeping them in sync can be a real pain.
How is dealt with this at IBM?
I agree. Not perfect. I don’t have a good answer.
that ‘s the trouble I’m facing … does it really don’t have any approach ? I try to combine all reused annotations into one, but we can not combine swagger annotations 🙁
http://www.intertech.com/Blog/spring-4-meta-annotations/
Is there a full working code example in the github? Without a test, no files are generated
Sorry, didn’t publish on GitHub. All code changes to the Spring sample “Building a RESTful Web Service” should be in the blog though.
check out https://github.com/springfox/springfox-demos
How do we get the output in the Swagger UI?
Sorry, no time to check. From the top of my head I used these URLs:
/greeting
/v2/api-docs?group=greetings
/swagger-ui.html
Thank you.
Amazing! thx!
Is there any possibility to add description to the place where “Response Class (Status 200)” is? This is only feature what I really miss there.
Barbora, if I understand you correctly, this is possible but I don’t know how from the top of my head. Here is an example which might help: https://watson-api-explorer.mybluemix.net/apis/tone-analyzer-v3-beta#!/tone/get_v3_tone
thanks for answer, in fact I was looking for @ApiOperation(notes = “Here is description of endpoint”)
And one more question, did you manage to add to swagger response headers? I tried this,but in UI is nothing @ResponseHeader(name = “location”, description = “URI of created resource”) }
Add “response = String.class”
@ResponseHeader(name = “location”, description = “URI of created resource”, response = String.class) }
I received the below response when i tried to access the Swagger doc:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Mon Apr 18 18:14:35 IST 2016
There was an unexpected error (type=Not Found, status=404).
No message available
Please help some into this.
Great Post. We are also using Swagger but we want to know best way to handle API versioning and it would be great if you can tell how IBM is handling it for internal projects.
thanks for providing such useful post. I have one query..what is the datatype for enum parameter. I checked with enum,Enum but it doesn’t identified it.
Hi,
I facing a problem while sending object in request payload through swagger:
My scenario is like this:
I have User class contains 10 fields, out of which my API required 4 fields to update my DB, but In currently it showing all 10 fields in request payload which may confuse API caller. Is there any ways to show only required fields in request payload in model schema.
Please help me to solve this issue.
Regards,
Gahininath
Worked for me
Nice. Is there a way to upload/place the existing swagger yaml file into the project code somewhere?
Is there a way to read and parse the Swagger docs other than doing “new SwaggerParser().read(“”)”? I am looking for a Spring implementation of Swagger Parser so I can autowire instead of using “new SwaggerParser()”.
Thanks for explanation,
Can I use same http code for multiple message in swagger document?
Ex : @ApiResponses(value = {
@ApiResponse(code = 400, message = “Invalid ID supplied”),
@ApiResponse(code = 400, message = “Id is null”),
})
Want to use 400 code for multiple scenario is it possible ?
Please help if
Hey
https://google.com/#btnI=rutigunu&q=ichatster.com&ab=gkxyaquyaf
My id #803095