Jersey 1.x Java service running on Tomcat 7




Summary

Jersey 1.x on Tomcat 7

  1. Tell Jersey about Swagger.
  2. Configure Swagger so that it knows a few things about your API.
  3. Annotate your resources so Swagger can serve them via its resource listing.
  4. Annotate your models so Swagger can include type information in its its resource listing.
  5. Optionally, put API access behind a key, basic auth or OAuth.

Dependencies

If you’re using maven you’ll need to add swagger’s library for Jersey 1.x to your pom.xml as shown below. Be sure to lookup the latest version number.

<dependency>
    <groupId>com.wordnik</groupId>
    <artifactId>swagger-jersey-jaxrs_2.10</artifactId>
    <version>1.3.5</version>
</dependency>

Configuration

Setup Jersey Servlet

Setup Jersey servlet which will serve your API resources. To do this, you need to tell Jersey which packages it should look for resources in. In addition to your own packages be sure to add these two swagger packages:

  1. com.wordnik.swagger.jaxrs.listing: Provides the main swagger resource listing at /api-docs path
  2. com.wordnik.swagger.jaxrs.json: This is a provider which configures JSON serialization.
<servlet>
    <servlet-name>jersey</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>
            com.wordnik.swagger.jaxrs.json;[your.service.package];com.wordnik.swagger.jaxrs.listing
        </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>


Required Swagger configuration

There are a couple of things you need to configure for your Swagger deployment. This includes:

  1. api.version: This is the version of your API so you can put what you want here.
  2. swagger.api.basepath: The basepath from which swagger resource listing is served.
<servlet>
    <servlet-name>DefaultJaxrsConfig</servlet-name>
    <servlet-class>com.wordnik.swagger.jaxrs.config.DefaultJaxrsConfig</servlet-class>
    <init-param>
        <param-name>api.version</param-name>
        <param-value>1.0.0</param-value>
    </init-param>
    <init-param>
        <param-name>swagger.api.basepath</param-name>
        <param-value>http://localhost:9090/api</param-value>
    </init-param>
    <load-on-startup>2</load-on-startup>
</servlet>

Optional Swagger configuration

If you like, you can also give the following information about your API to Swagger:

  1. title
  2. description
  3. termsOfServiceUrl
  4. contact
  5. license
  6. licenseUrl

Lets do this in a servlet too:

import com.wordnik.swagger.config.ConfigFactory;
import com.wordnik.swagger.model.ApiInfo;

public class Bootstrap extends HttpServlet {
  static {
        ApiInfo info = new ApiInfo(
          "Swagger Sample App",                             /* title */
          "This is a sample server Petstore server.  You can find out more about Swagger " + 
          "at <a href=\"http://swagger.wordnik.com\">http://swagger.wordnik.com</a> or on irc.freenode.net, #swagger.  For this sample, " + 
          "you can use the api key \"special-key\" to test the authorization filters", 
          "http://helloreverb.com/terms/",                  /* TOS URL */
          "apiteam@wordnik.com",                            /* Contact */
          "Apache 2.0",                                     /* license */
          "http://www.apache.org/licenses/LICENSE-2.0.html" /* license URL */
        );

        ConfigFactory.config.setApiInfo(info);
    }
}

And of course add this servlet to web.xml:

    <servlet>
        <servlet-name>Bootstrap</servlet-name>
        <servlet-class>com.wordnik.swagger.sample.Bootstrap</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>

Note that ConfigFactory.config, which we’re using in our sample Bootstap above, lets you configure several other properties programatically.

Annotate your code

All of the above was one time setup to activate Swagger into your service. However, it still does not know enough about your APIs. Sure jaxrs annotations on your API resources do give some information. However, we need to a way to tell Swagger the really good stuff about the APIs.

This is done via Swagger annotations. There is more information available in Swagger annotations javadoc but here is a breakdown of the various annotations that you can add to your API code to really Swaggerize it.

Annotating Resources

Here are the swagger annotations you can use to mark up your API Resource classes, their methods and parameters:


Class / @Api

@Api(value="/user", description = "Operations about user")
// other jaxrs annotations like @Path and @Produces
public class UserResource {
    // your resource code
}


Methods / @ApiOperation & @ApiResponse

public class UserResource {
    @ApiOperation(
        value = "Get user by user name",
        response = User.class,
        position = 0)
    @ApiResponses(value = {
        @ApiResponse(code = 400, message = "Invalid username supplied"),
        @ApiResponse(code = 404, message = "User not found") })
    // other jaxrs annotations like @Path and @GET/@POST/@DELETE
    public Response getUserByName(...) throws ApiException {
        // your resource method code
    }
}


Parameters / @ApiParam

public class UserResource {
    public Response getUserByName(
        // other jaxrs annotations like @PathParam/@QueryParam
        @ApiParam(
            value = "The name that needs to be fetched. Use user1 for testing. ", 
            required = true)  String username)
    throws ApiException {
}


A more complete Example showing both Swagger and jaxrs annotations for all three: Resource class, method and its parameters:

@Path("/user")
@Api(value="/user", description = "Operations about user")
@Produces({"application/json", "application/xml"})
public class UserResource {
    @GET
    @Path("/{username}")
    @ApiOperation(
        value = "Get user by user name",
        response = User.class,
        position = 0)
    @ApiResponses(value = {
        @ApiResponse(code = 400, message = "Invalid username supplied"),
        @ApiResponse(code = 404, message = "User not found")})
    public Response getUserByName(
        @ApiParam(
            value = "The name that needs to be fetched. Use user1 for testing. ", 
            required = true)
        @PathParam("username") String username)
    throws ApiException {
        // your method code
    }

  @GET
  @Path("/login")
  @ApiOperation(
        value = "Logs user into the system",
        response = String.class,
        position = 6)
  @ApiResponses(value = { 
        @ApiResponse(code = 400, message = "Invalid username/password supplied") })
  public Response loginUser(
        @ApiParam(
            value = "The user name for login", 
            required = true) 
        @QueryParam("username") String username,

        @ApiParam(
            value = "The password for login in clear text", 
            required = true) 
        @QueryParam("password") String password) {
        // your method code
  }


}


Annotating Models

How does Swagger figure out your API models?

Your APIs typically accept some input data and respond with some output data. Input data is implicitly expressed as parameters to your resource class methods. In jaxrs Swagger, output data is expressed using @ApiOperation’s response element. If your API contains multiple output types, you can express that using @ApiResponse’s response element.

So, by looking at data types of your API resource’s method params and by reading @ApiOperation.response + @ApiResponse.response, Swagger creates an inventory of the models that your API works wth. To enable swagger to do more with your models, you can annotate these model classes too.


Model class @ApiModel
@ApiModel(description = "An item which may be available in our grocery store")
public class GroceryItem {
    // your model properties
}


Model property @ApiModelProperty
@ApiModel(description = "An item which may be available in our grocery store")
public class GroceryItem {
    private String id, department;

    @ApiModelProperty(value = "unique identifier", allowableValues = "1,2,3")
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @ApiModelProperty(value = "department this item is found in")
    public String getDepartment() {
        return department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }
}


Here is a more complete example (in Scala) with subtypes:

@ApiModel(value="Animal", description="a model with subtypes", discriminator = "name", subTypes = Array(classOf[DomesticAnimal], classOf[WildAnimal]))
case class Animal (
  @(ApiModelProperty @field)(value = "name of animal", position = 1) name: String,
  @(ApiModelProperty @field)(value = "date added", position = 2) date: java.util.Date)

case class DomesticAnimal (
  @(ApiModelProperty @field)(value = "name of animal", position = 1) name: String,
  @(ApiModelProperty @field)(value = "animals are safe for children", position = 2) safeForChildren: Boolean,
  @(ApiModelProperty @field)(value = "date added", position = 3) date: java.util.Date)

case class WildAnimal (
  @(ApiModelProperty @field)(value = "name of animal", position = 1) name: String,
  @(ApiModelProperty @field)(value = "location found in", position = 2) foundInLocation: String,
  @(ApiModelProperty @field)(value = "date added", position = 3) date: java.util.Date)

Secure Swagger

Lets say that you want your API metadata exposed only to authorized callers. In Swagger you can apply authorization at operation method level. Three authorization schemes are supported by the specification: OAuth, Basic Auth and API Key.

TODO-

Details need to be added but reading this should give you a head start.

Sample Service

You can see a sample service for Jersey 1 on Tomcat 7. To run it:

git clone git@github.com:ayush/swagger-samples.git
cd swagger-samples/service/java/tomcat-7-jersey-1
mvn tomcat7:run

You can then see: