Jay Taylor's notes

back to listing index

Swagger: A simple, open standard for describing REST APIs with JSON

[web search]
Original source (swagger.wordnik.com)
Tags: swagger.wordnik.com
Clipped on: 2012-08-07

Swagger Specification

Core to Swagger is the specification of RESTful web services. This includes three major components: resource discovery, resource declaration and input/output model declaration. Let’s explore each component in more detail.

Resource Discovery

The resource discovery mechanism is akin to a sitemap for your web services—based on access (covered below), API consumers are presented with a list of available resources. Both the client generator and the UI documentation sandbox start with the resource discovery URL, which shows “where to go” for more information.

Resource Declaration

At the heart of Swagger is the resource declaration. This describes the APIs provided by the system and the required and optional fields for each operation. The resource declaration also provides information on the allowable inputs and describes complex objects transmitted to and from the API, as well as the error conditions that can occur if something goes wrong.

The Resource Declaration includes the following:

basePathThe fixed portion of the API being declared. All API paths are relative to this basePath.
swaggerVersionThe version of the Swagger specification implemented by this provider.
apiVersionThe version of the implemented API.
apisAn array of APIs available to the client.
modelsAn array of models used in this API.

APIs

Each element in the APIs array is a logical grouping of possible operations on a fixed path. For example a GET and DELETE operation against the same URL would be described in a single API element.

Parameters for each operation come in a number of flavors, which correspond to typical REST patterns. They are named in the name attribute and are described by the paramType attribute. The allowable paramType values are:

pathThe input is part of the URL itself, specifically the URL portion which corresponds to the {name} in the API path. All path parameters are mandatory and must be non-zero length.
queryThe input is specified by a key/value query param in the form of {key}={value}. Multiple query parameters are separated by “&” delimiters.
postOne and only one input object is supplied as part of a HTTP post operation. This is the only supported mechanism for supplying complex objects to the operations.

Other self-explanatory attributes of the API object:

dataType The primitive type (see Appendix A ) of the allowable input values for query and path params. For post params, complex datatypes are supported per the models section. Even though query and path params are passed as part of the URI, specifying the type (Integer, String) can help the client send appropriate values.
responseClass This declares the class of the model being returned from the API operation. See Appendix B.
allowableValuesFor query parameters, this outlines the options that the client can supply. The Swagger framework does not enforce that the client conforms to the allowable values—that is the job of the underlying server implementation.
allowMultipleFor query parameters, this signals to the client that multiple values can be specified in a comma-separated list.

errorResponses

Each API has a corresponding array of errorResponse objects. These describe the possible error codes and what they mean to the client (note: a HTTP 500 error response is always possible and implicit).

Error response objects contain the following attributes:

code The HTTP error code returned. See en.wikipedia.org/wiki/List_of_HTTP_status_codes for a complete list.
reason A human-readable reason for the error, applicable to this operation. Note that returning a 404 error response will tell you “not found” but for usability, the error code should be more explicit with reasons like “user was not found” to avoid confusion between general service availability and application logic. It is important to note that HTTP as a protocol is somewhat abstracted from the framework. That said, Swagger offers an exception mapper which will catch application-level exceptions and map them to HTTP responses.
models The models array describes complex objects which can be passed to and from the API. In the description of each object there is no effort put into describing an entire object graph—instead complex sub-objects have named types, which each have their own model description. All models will eventually devolve into primitives. The model description follows draft 3 of the JSON schema as submitted to the IETF. For more information please see: tools.ietf.org/html/draft-zyp-json-schema-03

Wordnik Swagger Framework Implementation

The Swagger specification is fully implemented by Wordnik and available to open source as a series of tools and libraries. See downloads.

Server

Given the goal of having a server-driven API framework, this component is core to Swagger. It is implemented by an OSS server library and depends on a number of OSS projects. The core requirements for integrating include:

  • Java runtime. Version 1.6 or greater is required—internal testing uses the Oracle JVM runtime from http://java.oracle.com.
  • Scala runtime. Version 2.8.1 final or greater is required. Scala is available from scala-lang.org
  • Jersey framework. Version 1.7 or greater of the JAX-RS framework is required.
  • Jackson JSON parser. Version 1.7.7 or greater of the Jackson JSON library is required.
  • ant and ivy. Both Apache projects are available from http://apache.org.
  • The Swagger specification is achieved by annotating JAX-RS-aware classes with a series of annotations. These declare the endpoints, parameters, and return types. In addition the decoration of models with JAXB annotations makes them automatically discoverable and describable by the Swagger framework.

Since Swagger supports both XML and JSON formats, all examples declare their format in the resource itself. While not required by the specification—desired format can be supplied in request headers —- it is strongly encouraged that the system have explicit paths for XML and JSON. You will continue to see this style throughout this documentation and on all Swagger-related examples either explicitly or with a .{format} placeholder.

Resource Discovery

Resources are declared automatically by the com.wordnik.swagr.sandbox.resource.ApiListingResource. This will tell the Swagger framework to introspect and instrument all JAX-RS instrumented classes specified in the com.sun.jersey.config.property.packages parameter in the web.xml. See Appendix D for an example. Once instrumented, a resource is automatically made available in the {ws-context}/resources.{format}

Resource Annotations

The following are required for proper code annotation:

@Api This tells the framework about a top-level resource (i.e. api.wordnik.com/v4/{resource}.{format} ). This differs from the @Path annotation—this is to allow for the same instrumentation to be supplied for a number of request and response formats. So the resources /v4/words.json and /v4/words.xml would be annotated as @Api("/words").
valueThe short description of what the API does.
descriptionA longer description of what the API does.

Operation Annotations

The @ApiOperation annotation allows for the instrumentation of a single API operation. The annotation also considers the following method-level annotations:

@GET @POST @PUT @DELETEThese JAX-RS annotations indicate what type of HTTP operation the method is.
@PathAlso a JAX-RS annotation, this indicates the URI relative to the base path in the @Api annotation.
@ApiErrorsThis is an array of @ApiError annotations (below) which describe possible error conditions for the operation.
@ApiErrorThis describes a specific error reason and HTTP response code.

In addition, the @ApiOperation supports the following attributes:

valueThis is the human-readable description of what the API does.
responseClass The fully-qualified response model to be returned from the operation. For instrumentation, this requires the full package specifier. For primitives, simply specify any one of the values listed in Appendix A.
@multiValueResponse This indicates that the response contains an array of responseClass objects.
tags This is a comma-separated list of tag strings which can be used to group operations. Tags are optional in Swagger.

Parameter Annotations

Following the JAX-RS style annotations, the input values to methods are annotated with Swagger annotations to construct the schema. Specifically, @ApiParam is an annotation on a particular method input value. It supports the following values:

valueThis is the human-readable description of what the parameter is.
required For post and query params (see full compatibility table in Figure 1), this can indicate whether the value is optional or mandatory.
allowMultipleFor query params, indicates whether multiple values are allowed (choice vs. option).
allowableValuesIndicates supported, allowable values for the parameter

See Appendix D for an example.

Security

Swagger provides a general mechanism for API security. Based on a filter, the server can be implemented with virtually any type of security. Note the security implementation is left for the API developer to create. The input to the filter interface is:

apiPath:StringThe full path to the method being called.
headers:HttpHeadersAll headers supplied in the request to the api as detected by the JAX-RS implementation.
uriInfo:UriInfoAdditional URI information provided by the JAX-RS implementation.

This mechanism secures resources based on operations being requested. Object-level security should be implemented “on the other side” of Swagger—namely in the API layer of the application.

Client Library Generator

Since all Swagger-compliant APIs expose a Resource Declaration, client libraries can be automatically generated for any language. The client generator can read both resource methods and models to generate a fully-capable REST client.

The Client Library Generator utilizes the Antlr String Template Library (http://www.stringtemplate.org/) to process a small number of code templates against the response of the Resource Declaration query against the server. The output from the generator is a light-weight client library for use in a number of target languages.

In addition, the Client Library Generator includes a test framework for running client-side tests against a Swagger-compatible server. This includes response checking as well as a template for verifying expected responses.

Developer Site/API Sandbox

The Swagger framework includes an HTML5 + javascript-based API Sandbox. The tool needs only a Resource Discovery URL (i.e. http://api.wordnik.com/v4/resources.json) and an API key. The tool can then be used to browse and test any API which implements the Swagger specification.

The sandbox is useful for understanding the routes that the particular API key has access to. Filtering of resources is applied automatically to any resource list based on an implementation of the ApiAuthorizationFilter. So your users will only see their resources. Each method appears in its own line in the UI with color coding & grouping based on the HTTP method type.

The UI stores the Resource Discovery URL and API key in the browser’s local storage. The UI can be delivered to developers as either a local application or by deploying it on a remote server.

As multiple resources are encountered the UI will group them appropriately, see the /pet and /store resource examples in the sandbox UI.

Currently only GET is supported with the sandbox.

Appendix A: Allowable Primitive Datatypes

  • String
  • Integer
  • Long
  • Double
  • Boolean (true | false, yes | no are all treated case-insensitive)
  • Dates should be described as String values in ISO-8601 format and de-serialized using the convenience methods in the server implementation.

Appendix B: Sample Model Response

From the sample app at http://localhost:8002/swagger-sample-app/api/note.json (Note how the embedded "photo" object is declared elsewhere in the model tree. Model declarations do not include sub-objects.)

"note":{
    "properties":{
        "description":{
            "type":"string"
        },
        "longValue":{
            "type":"long"
        },
        "name":{
            "type":"string"
        },
        "date":{
            "type":"Date"
        },
        "photo":{
            "type":"photo"
        },
        "booleanValue":{
            "type":"boolean"
        },
        "intValue":{
            "type":"int"
        }
    },
    "id":"note"
}
"photo":{
    "properties":{
        "title":{
            "type":"string"
        },
        "url":{
            "type":"string"
        }
    },
    "id":"photo"
}

Appendix C: Sample Resource and Operation Listings

// Sample resource listing
{
  "apis":[
    {
      "path":"/photo",
      "description":""
    }
  ],
  "basePath":"url",
  "swagrVersion":"0.1a",
  "apiVersion":"1.0.1a"
}

// Sample operation listing
{
  "apis":[
    {
      "path":"/photo/{userId}",
      "description":"",
      "operations":[
        {
          "parameters":[
            {
              "name":"userId",
              "description":"ID of User whose photos",
              "dataType":"string",
              "allowMultiple":false,
              "required":true,
              "allowableValues":[
                "allowedId1",
                "allowedId2",
                "allowedId3"
              ],
              "paramType":"path"
            }
          ],
          "httpMethod":"GET",
          "tags":[
            "DM",
            "PD"
          ],
          "nickname":"getPhotosById",
          "responseClass":"List[photo]",
          "deprecated":false,
          "open":false,
          "summary":"Fetches photos by UserId"
        }
      ],
      "errorResponses":[
        {
          "reason":"Invalid ID supplied",
          "code":400
        },
        {
          "reason":"Not Authorized to access User",
          "code":403
        },
        {
          "reason":"User not found",
          "code":404
        }
      ]
    }
  ],
  "models":{
    "photo":{
      "properties":{
        "title":{
          "type":"string"
        },
        "url":{
          "type":"string",
          "description":"Url for photo",
          "access":"restricted",
          "notes":"Sample note for a url",
          "enum":[
            "a",
            "b",
            "c"
          ]
        }
      },
      "id":"photo"
    }
  },
  "basePath":"url",
  "swagrVersion":"0.1a",
  "apiVersion":"1.0.1a"
}

Appendix D: Sample Resource and Operation Annotations

// Sample resource annotation
@Path("/photo.json")
@Api("/photo")
@Produces(Array("application/json"))
class PhotoResourceJSON extends Help
  with PhotoResource

// Sample method annotation
@GET
@Path("/{userId}")
@ApiOperation(
  value = "Fetches photos by UserId",
  responseClass = "com.wordnik.swagr.sandbox.data.Photo",
  mutiValueResponse = true,
  tags = "DM,PD"
)
@ApiErrors(Array(
  new ApiError(code = 400, reason = "Invalid ID supplied"),
  new ApiError(code = 403, reason = "Not Authorized to access User"),
  new ApiError(code = 404, reason = "User not found")))
def getPhotosById(
  @ApiParam(
    value="ID of User whose photos need to be fetched",
    required=true,
    allowMultiple=false,
    allowableValues="allowedId1,allowedId2,allowedId3")
  @PathParam("userId") userId: String) = {
    Response.ok.entity(PhotoApi.getPhotos(userId)).build
  }

Whitepaper

This document is also available as a PDF: swagger-final-1.0.pdf