Spring Rest API with Swagger – Creating documentation

The real key to making your REST API easy to use is good documentation. But even if your documentation is done well, you need to set your company processes right to publish it correctly and on time. Ensuring that stakeholders receive it on time is one thing, but you are also responsible for updates in both the API and documentation. Having this process done automatically provides easy way out of trouble, since your documentation is no longer static deliverable and becomes a living thing. In previous post, I discussed how to integrate Swagger with your Spring application with Jersey. Now it’s time to show you how to create documentation and publish it for others to see.

Before I get down to the actual documentation, lets start with a few notes on its form and properties. We will be using annotations to supply metadata to our API which answers question how. But what about why? On one hand we are supplying new annotations to already annotation ridden places like API endpoints or controllers (in case of integration with Spring MVC). But on the other, this approach has a standout advantage in binding release cycle of application, API and documentation in one delivery. Using this approach allows us to create and manage small cohesive units ensuring proper segmentation of documentation and its versioning as well.

Creating endpoint documentation

Everything starts right on top of your endpoint. In order to make Swagger aware of your endpoint, you need to annotate your class with @Api annotation. Basically, all you want to do here is name your endpoint and provide some description for your users. This is exactly what I am doing in the following code snippet. If you feel the need to go into more detail with your API documentation, check out @Api annotation description below.

package com.jakubstas.swagger.rest;

/**
 * REST endpoint for user manipulation.
 */
@Api(value = "users", description = "Endpoint for user management")
@Path("/users")
public class UsersEndpoint {
    ...
}

To verify the results just enter the URL from your basePath variable followed by /api-docs into your browser. This is the place where resource listing for your APIs resides. You can expect something similar to following snippet I received after annotating three of my endpoints and accessing http://[hostname]:[port]/SpringWithSwagger/rest/api-docs/:

{
    "apiVersion":"1.0",
    "swaggerVersion":"1.2",
    "apis":[
        {
            "path":"/users",
            "description":"Endpoint for user management"
        },
        {
            "path":"/products",
            "description":"Endpoint for product management"
        },
        {
            "path":"/employees",
            "description":"Endpoint for employee listing"
        }
    ]
}

However, please note that in order for an API to appear in APIs listing you have to annotate at least one API method with Swagger annotations. If none of your methods is annotated (or you haven’t provided any methods yet), API documentation will not be processed and published.

@Api annotation
Describes a top-level api. Classes with @Api annotations will be included in the resource listing.

Annotation parameters:

  • value – Short description of the Api
  • description – general description of this class
  • basePath – the base path that is prepended to all @Path elements
  • position – optional explicit ordering of this Api in the resource listing
  • produces – content type produced by this Api
  • consumes – media type consumed by this Api
  • protocols – protocols that this Api requires (i.e. https)
  • authorizations – authorizations required by this Api

Operations documentation

Now, lets move on to the key part of API documentation. There are basically two main parts of operation documentation – operation description and response description. Lets start with operation description. Using annotation @ApiOperation provides detailed description of what certain method does, its response, HTTP method and other useful information presented in annotation description below. Example of operation declaration for Swagger can be seen in the following code sample.

@ApiOperation annotation
Describes an operation or typically a HTTP method against a specific path. Operations with equivalent paths are grouped in an array in the Api declaration.

Annotation parameters:

  • value – brief description of the operation
  • notes – long description of the operation
  • response – default response class from the operation
  • responseContainer – if the response class is within a container, specify it here
  • tags – currently not implemented in readers, reserved for future use
  • httpMethod – the HTTP method, i.e GET, PUT, POST, DELETE, PATCH, OPTIONS
  • position – allow explicit ordering of operations inside the Api declaration
  • nickname – the nickname for the operation, to override what is detected by the annotation scanner
  • produces – content type produced by this Api
  • consumes – media type consumed by this Api
  • protocols – protocols that this Api requires (i.e. https)
  • authorizations – authorizations required by this Api

You may notice the use of response parameter in @ApiOperation annotation that specifies type of response (return type) from the operation. As you can see this value can be different from method return type, since it serves only for purposes of API documentation.

@GET
@Path("/{userName}")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Returns user details", notes = "Returns a complete list of users details with a date of last modification.", response = User.class)
@ApiResponses(value = {
    @ApiResponse(code = 200, message = "Successful retrieval of user detail", response = User.class),
    @ApiResponse(code = 404, message = "User with given username does not exist"),
    @ApiResponse(code = 500, message = "Internal server error")}
)
public Response getUser(@ApiParam(name = "userName", value = "Alphanumeric login to the application", required = true) @PathParam("userName") String userName) {
    ...
}

Next, take a look at the use of @ApiParam. It is always useful to describe to the client what you need in order to fulfill their request. This is the primary aim of @ApiParam annotation. Whether you are working with path or query parameter, you should always provide clarification of what this parameter represents.

@ApiParam annotation
Represents a single parameter in an Api Operation. A parameter is an input to the operation

Annotation parameters:

  • name – name of the parameter
  • value – description of the parameter
  • defaultValue – default value – if e.g. no JAX-RS @DefaultValue is given
  • allowableValues – description of values this endpoint accepts
  • required – specifies if the parameter is required or not
  • access – specify an optional access value for filtering in a Filter implementation. This allows you to hide certain parameters if a user doesn’t have access to them
  • allowMultiple – specifies whether or not the parameter can have multiple values provided

Finally, lets look at the way of documenting the actual method responses in terms of messages and HTTP codes. Swagger comes with @ApiResponse annotation, which can be used multiple times when it’s wrapped using @ApiResponses wrapper. This way you can cover all alternative execution flows of your code and provide full API operation description for clients of your API. Each response can be described in terms of HTTP return code, description of result and type of the result. For more details about @ApiResponse see description below.

@ApiResponse annotation
An ApiResponse represents a type of response from a server. This can be used to describe both success codes as well as errors. If your Api has different response classes, you can describe them here by associating a response class with a response code. Note, Swagger does not allow multiple response types for a single response code.

Annotation parameters:

  • code – response code to describe
  • message – human-readable message to accompany the response
  • response – optional response class to describe the payload of the message

Using these annotations is pretty simple and provides nicely structured approach to describing features of your API. If you want to check what your documentation looks like just enter the URL pointing to the API documentation of one of your endpoints by appending the value of parameter value from @Api annotation to the URL pointing to resource listing. Be careful no to enter the value of @Path annotation be mistake (unless they have the same value). In case of my example desired URL is http://[hostname]:[port]/SpringWithSwagger/rest/api-docs/users. You should be able to see output similar to following snippet:

{  
    "apiVersion":"1.0",
    "swaggerVersion":"1.2",
    "basePath":"http://[hostname/ip address]:[port]/SpringWithSwagger/rest",
    "resourcePath":"/users",
    "apis":[  
        {  
            "path":"/users/{userName}",
            "operations":[  
                {  
                    "method":"GET",
                    "summary":"Returns user details",
                    "notes":"Returns a complete list of users details with a date of last modification.",
                    "type":"User",
                    "nickname":"getUser",
                    "produces":[  
                        "application/json"
                    ],
                    "authorizations":{  

                    },
                    "parameters":[  
                        {  
                            "name":"userName",
                            "description":"Alphanumeric login to application",
                            "required":true,
                            "type":"string",
                            "paramType":"path",
                            "allowMultiple":false
                        }
                    ],
                    "responseMessages":[  
                        {  
                            "code":200,
                            "message":"Successful retrieval of user detail",
                            "responseModel":"User"
                        },
                        {  
                            "code":404,
                            "message":"User with given username does not exist"
                        },
                        {  
                            "code":500,
                            "message":"Internal server error"
                        }
                    ]
                }
            ]
        }
    ],
    "models":{
        "User":{
            "id":"User",
            "properties": {
                "surname":{"type":"string"},
                "userName":{"type":"string"},
                "lastUpdated":
                    {
                        "type":"string",
                        "format":"date-time"
                    },
                "avatar":{
                    "type":"array",
                    "items":{"type":"byte"}
                },
                "firstName":{"type":"string"},
                "email":{"type":"string"}
            }
        }
    }
}

Creating model documentation

By supplying User class to the response parameter of several annotations in previous example, I’ve managed to introduce new undocumented element into my API documentation. Swagger was able to pull out all the structural data about User class with no regard for its relevance to the API. To counter this effect, Swagger provides two annotations to provide additional information to the users of your API and restrict visibility of your model. To mark a model class for processing by Swagger just place @ApiModel on top of your class. As usual, you can provide description as well as inheritance configuration. For more information see @ApiModel description below.

@ApiModel annotation

A bean class used in the REST-api. Suppose you have an interface @PUT @ApiOperation(…) void foo(FooBean fooBean), there is no direct way to see what fields FooBean would have. This annotation is meant to give a description of FooBean and then have the fields of it be annotated with @ApiModelProperty.

Annotation parameters:

  • value – provide a synopsis of this class
  • description – provide a longer description of the class
  • parent – provide a superclass for the model to allow describing inheritance
  • discriminator – for models with a base class, a discriminator can be provided for polymorphic use cases
  • subTypes

Last thing you need to do is to annotate class members with @ApiModelProperty annotation to provide documentation for each class member. Simple example of this can be seen in the following class.

package com.jakubstas.swagger.model;

@ApiModel
public class User {

    private String userName;

    private String firstName;

    private String surname;

    private String email;

    private byte[] avatar;

    private Date lastUpdated;

    @ApiModelProperty(position = 1, required = true, value = "username containing only lowercase letters or numbers")
    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    @ApiModelProperty(position = 2, required = true)
    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    @ApiModelProperty(position = 3, required = true)
    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    @ApiModelProperty(position = 4, required = true)
    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @JsonIgnore
    public byte[] getAvatar() {
        return avatar;
    }

    public void setAvatar(byte[] avatar) {
        this.avatar = avatar;
    }

    @ApiModelProperty(position = 5, value = "timestamp of last modification")
    public Date getLastUpdated() {
        return lastUpdated;
    }

    public void setLastUpdated(Date lastUpdated) {
        this.lastUpdated = lastUpdated;
    }
}

If you need to provide more details about your model, check following description of @ApiModelProperty:

@ApiModelProperty annotation
An ApiModelProperty desecribes a property inside a model class. The annotations can apply to a method, a property, etc., depending on how the model scanner is configured and used.

Annotation parameters:

  • value – Provide a human readable synopsis of this property
  • allowableValues – If the values that can be set are restricted, they can be set here. In the form of a comma separated list registered, active, closed
  • access – specify an optional access value for filtering in a Filter implementation. This allows you to hide certain parameters if a user doesn’t have access to them
  • notes – long description of the property
  • dataType – The dataType. See the documentation for the supported datatypes. If the data type is a custom object, set it’s name, or nothing. In case of an enum use ‘string’ and allowableValues for the enum constants
  • required – Whether or not the property is required, defaults to false
  • position – allows explicitly ordering the property in the model. Since reflection has no guarantee on ordering, you should specify property order to keep models consistent across different VM implementations and versions

If you follow these instructions carefully, you should end up with complete API documentation in json on previously mentioned URL. Following is only model related part of resulting json, now with provided documentation.

{
    ...
    "models":{  
        "User":{  
            "id":"User",
            "description":"",
            "required":[  
                "userName",
                "firstName",
                "surname",
                "email"
            ],
            "properties":{  
                "userName":{  
                    "type":"string",
                    "description":"username containing only lowercase letters or numbers"
                },
                "firstName":{  
                    "type":"string"
                },
                "surname":{  
                    "type":"string"
                },
                "email":{  
                    "type":"string"
                },
                "lastUpdated":{  
                    "type":"string",
                    "format":"date-time",
                    "description":"timestamp of last modification"
                }
            }
        }
    }
}

What is next?

If you followed all steps you should now have working API documentation that may be published or further processed by automation tools. I will showcase how to present API documentation using Swagger UI module in my next article called Spring Rest API with Swagger – Exposing documentation. The code used in this micro series is published on GitHub and provides examples for all discussed features and tools. Please enjoy! 🙂

Update 06.04.2015: Since some users reported issues with updating the dependencies used in my example project I decided to create a second project for Spring 4 to provide distinct solutions for both Spring 3 and Spring 4.

29 thoughts on “Spring Rest API with Swagger – Creating documentation

    1. Hi Camilo, thank you. I don’t know if I understood you correctly but when I modify Employee class like this:

      @ApiModelProperty(value = “Property Name”, required = true)
      public String getFirstName() {
      return firstName;
      }

      I end up with following json:

      “properties”:{
      “firstName”:{
      “type”:”string”,
      “description”:”Property Name”
      },
      “surname”:{
      “type”:”string”
      },
      “employeeNumber”:{
      “type”:”integer”,
      “format”:”int32″
      }
      }

      and Swagger UI displays following response model:

      Employee {
      firstName (string): Property Name,
      surname (string),
      employeeNumber (integer)
      }

  1. Hi! Nice Documentation! Helped me a lot.
    @ApiResponse(code = 200, message = “A list of found users”, response=List.class)

    But in detail the list is List
    How can I annotate this? So that my api-docs shows me the information about the response that it is a List

    Further on, is it possible to create some kind of object-reference-navigation? For excample in the swagger.io.
    If response is UserBean.class which contains for example an AddressBean.class ?

    1. Hi Tom,

      thank you. Let me start with your List-related question. As far as I know, it is possible to set response type to a collection by using parameter responseContainer of annotation @ApiOperation with possible values: List, Array (no difference between them) and Set. So you can use this to specify response value to be the collection of type specified by the class passed to the response parameter of the very same annotation. The difference in resulting documentation is visible in both the json and Swagger UI. As an example consider following modification to my EmployeeEndpoint class – changing @ApiOperation annotation to following:

      @ApiOperation(value = "Returns all employees", notes = "Returns a complete list of employees.", responseContainer = "List", response = Employee.class)
      

      On json level, the old "type":"Employee" will be replaced by something similar to this "type":"array","items":{"$ref":"Employee"}. Let say ‘typed collection’. However, on Swagger UI level, it is much harder to spot the change. Yet, there is one :). If you pay close attention to the response class model schema portion of documentation, you will notice the change from:

      {
         "firstName": "",
         "surname": "",
         "employeeNumber": 0
      }
      

      to

      [
         {
            "firstName": "",
            "surname": "",
            "employeeNumber": 0
         }
      ]
      

      And to answer your second question – there is something, but it is not reference navigation. However, if I create Address.class with a single property and include it in my Employee.class, I will end up with all the model objects documented in Response messages model portion of documentation. Following is the resulting Swagger UI of my experiment with address.

      Hope it helps 🙂

      1. Hi Jakub! Thanks for the fix reply! Sorry, I have not seen that the post get swallowed all my +lt; +gt;
        It reads like a confused text. But you got it.

        It’s a shame that it’s not possible to return more complex Objects like Maps with further information about their input.

        And am I right that there is also no possibility out of the box to create a documentation about all my Beans without using them in special resources as return response?

        Would be nice to give a swagger-project my package tom.java.beans.* and it will document it.

        1. Hi Tom, thanks for pointing out the behavior of comment section. I wasn’t satisfied with it myself so I decided to enable Jetpacks markdown support so you should be able to use markdown without loosing any characters 🙂 Sorry about that.

          I honestly don’t know if there is solution ready, when it comes to the ‘bean related’ documentation. There might be some sort of maven plugin or something that might generate some sort of docs for this case. I encourage you to check with the vendor or at least check available plugins.

  2. An unwanted http status code 200 is displaying in response message section in swagger UI even though i have declared useDefaultResponseMessages(false) for SwaggerSpringMvcPlugin and i have set the API response values as
    @ApiResponses(value = {
    @ApiResponse(code = 204, message = “Asset shared successfully”, response = Response.class),
    @ApiResponse(code = 422, message = “Request is not valid”, response = ErrorResource.class),
    @ApiResponse(code = 500, message = “Internal server error occured”, response = Response.class) })

    I am using swagger 1.0.2

    1. Hi Kalyan, I am afraid I won’t be of any help here since I have not tried Spring MVC plugin integration.

  3. Hey, I can only get the bean config presented:

    {
    "apiVersion": "1.1",
    "swaggerVersion": "1.2",
    "info": {
    "title": "title",
    "description": "descr",
    "contact": "contact"
    }
    }

    but not the classes I annotated. I do set the ResourcePackage correctly and Scan is true, but nothing happens.

    1. What do you see when you crank up the logging level during context initialization? Can you see the classes you annotated being picked up and processed? Unless you can see this (under DEBUG level I believe) you didn’t set your resource scanning properly.

  4. Something is wrong with Annotation parameters in expanding sections in the article. I don’t think that they should look like this: MARKDOWN_HASH2063c1608d6e0baf80249c42e2be5804MARKDOWN_HASH

    1. Hi Mikhail, thanks for pointing that out. It seems like two of the plugins I use clash when <code> tag is being used. Should be fine now.

  5. Hi Jakub,

    my json:
    {
    "name": "string",
    "wareHouseID": "Integer",
    "company": "string",
    "fullname": "string",
    "address": "string",
    "parentID": "int"
    }

    How to get value of “wareHouseID”:0 , my code:

    private Integer wareHouseID;
    private int parentID;
    private String name;
    private String fullname;
    private String company;
    private String address;

    public Warehouse() {
    }

    @ApiModelProperty(position = 1,required = true, dataType = "java.lang.Integer")
    public Integer getWareHouseID() {
    return wareHouseID;
    }

    public void setWareHouseID(Integer wareHouseID) {
    this.wareHouseID = wareHouseID;
    }

    Thanks 🙂

  6. Hello Jakub,

    I am not able to see the methods which I have annotated with Swagger annotation as part of operations within api-docs. Any suggestions? This is how the api-docs json looks like :

    {
        "apiVersion":"1.0",
        "swaggerVersion":"1.2",
        "apis":[
            {
                "path":"/owner",
                "description":"Owner Service API"
            }
        ]
    }
  7. Hi, I am facing issue where I see duplicates REST API docs are coming. How could we solve this error ?

    1. Hi Deepak, I would recommend increasing logging and checking how are your objects registered and handled. Logs usually show you where to look for the answer.

  8. Thanks for posting Jakub Stas. I was looking for hours how to add field documentation to swagger. Your post is more detailed than swagger documentation!

  9. Jakub,

    In this line:

    @ApiResponse(code = 200, message = “Successful retrieval of user detail”, response = User.class)

    If the User class contained a Timestamp, say “creationDate,” Swagger displays the response model schema, for that field, as:

    creationDate”: {
    “date”: 0,
    “day”: 0,
    “hours”: 0,
    “minutes”: 0,
    “month”: 0,
    “nanos”: 0,
    “seconds”: 0,
    “time”: 0,
    “timezoneOffset”: 0,
    “year”: 0
    }, …

    How can I prevent that? In other words, my API returns this:

    “creationDate”: 1284736980000

    I’ve looked up some solutions based on “ModelConverters,” but not sure how this can be implemented in Java. Do you or anyone else have a link or feedback regarding this?

    Thanks!

    1. Actually, nevermind. 🙂

      I realized I could use the “example” keyword on the ApiModelProperty annotation for that.

      Thanks anyways! And great job on your blog posts!

  10. Hi,
    My requirement is for date field, In swagger documentation issuedate showing date in datetimestamp like “2020-06-15T09:21:29.699Z”,

    If User input date in similar format my application process this correctly, but if user input value in simple date format like “2020-06-15″ (yyyy-MM-dd) this will get pass null value in respective field and failed in validation for mandatory field verification.
    @ApiModelProperty(value=”Details”, required=true, dataType=”sampleDto”, notes=”Transaction Details”)

    dto object: sampleDto
    sampleDto.java:

    import com.fasterxml.jackson.annotation.JsonFormat;
    import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
    import com.fasterxml.jackson.annotation.JsonInclude;
    import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
    import io.swagger.annotations.ApiModelProperty;

    @JsonIgnoreProperties(ignoreUnknown = true)
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public class sampleDto {
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = “yyyy-MM-dd”)
    @ApiModelProperty(name= “issuedate”, value = “Indicates Issue Date”, required=true , dataType=”java.sql.date”)
    //getter setter added here
    }

Leave a Reply

Your email address will not be published. Required fields are marked *