Skip to content

Swagger 2.X Getting started

Francesco Tumanischvili edited this page Apr 11, 2018 · 6 revisions

NOTE: Swagger Core 2.X produces OpenApi 3.0 definition files. If you're looking for swagger 1.5.X and OpenApi 2.0, please refer to 1.5.X JAX-RS Setup

What is it about?

NOTE: swagger-core is based on OpenAPI specification; check out related docs for an overview of Swagger ecosystem.

swagger-core is an open source Java implementation of Swagger/OpenAPI, providing:

  • swagger-models: OpenAPI specification Java implementation
  • swagger-core: resolves (annotated) java POJOs into OpenAPI schemas, handles serialization/deserialization and provides an integration mechanism.
  • swagger-jaxrs2: resolves JAX-RS (annotated) resources into an OpenAPI definition, and provides an integration mechanism.
  • swagger-annotations: a set of annotations to declare and manipultate output generated by swagger-core, swagger-jaxrs2 and/or other projects.

Where to start

One of the common usage scenarios is to integrate swagger-jaxrs2 into an existing or new JAX-RS based project ("code-first"), to automatically provide and expose its APIs definition, which is kept in sync during the project lifecycle. Such definition can be the base for further processing/consumption, including API documentation (e.g with swagger-ui, API client generation in various languages (e.g with swagger-codegen), custom processing, and so on.

Such result is achieved by scanning JAX-RS resources and resolving their operations and used types, (also) processing applied annotations (e.g. Swagger, JAX-RS, Jackson, JAXB, etc.). An extension mechanism allows to further customize and pre/post processing result.

Check out Quick start below, or jump to Integration and configuration.

Quick start

Swagger uses maven for build and deployment and its artifacts are available at Maven Central. You can use the maven dependencies with any dependency management system that supports maven dependencies such as Maven, Ivy and Gradle. If you're not using Maven, please refer to Not using Maven

Integrating swagger-core into a JAX-RS application can be as easy as adding its dependency to the project POM:

  <dependencies>
    ...
    <dependency>
      <groupId>io.swagger.core.v3</groupId>
      <artifactId>swagger-jaxrs2</artifactId>
      <version>2.0.0</version>
    </dependency>
    <dependency>
      <groupId>io.swagger.core.v3</groupId>
      <artifactId>swagger-jaxrs2-servlet-initializer</artifactId>
      <version>2.0.0</version>
    </dependency>
  </dependencies>

Consider a simple scenario, consisting in a JAX-RS application (e.g. Jersey or RESTEasy) with a resource like:

@Path("/pet")
@Produces({"application/json", "application/xml"})
public class PetResource {

  @GET
  @Path("/{petId}")
  public Pet getPetById(@PathParam("petId") Long petId) throws io.swagger.sample.exception.NotFoundException {
      // return pet
      return new Pet();
  }

  @POST
  @Consumes("application/json")
  public Response addPet(
      @Parameter(description = "Pet object that needs to be added to the store", required = true) Pet pet) {
    // add pet
    return Response.ok().entity("SUCCESS").build();
  }
}

and related model POJO:

@XmlRootElement(name = "Pet")
public class Pet {
  private long id;
  private String name;
  private List<Tag> tags = new ArrayList<Tag>();

  @XmlElement(name = "id")
  public long getId() {
    return id;
  }

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

  @XmlElement(name = "name")
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  @XmlElementWrapper(name = "tags")
  @XmlElement(name = "tag")
  public List<Tag> getTags() {
    return tags;
  }

  public void setTags(List<Tag> tags) {
    this.tags = tags;
  }
}

Just by adding the dependencies, an endpoint <server_url>/<application_path>/openapi.json (and openapi.yaml) is activated, exposing the OpenAPI definition of the app APIs serialized as json or yaml, as resolved by swagger-core processing JAX-RS resources defined in the application.
NOTE: The endpoint is fully configurable and/or the definition endpoint can be provided by application defined resources. See Integration and configuration

Given the resource above, the resolved spec looks like:

openapi: 3.0.1
paths:
  /sample/pet/{petId}:
    get:
      operationId: getPetById
      parameters:
      - name: petId
        in: path
        required: true
        schema:
          type: integer
          format: int64
      responses:
        default:
          description: default response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
            application/xml:
              schema:
                $ref: '#/components/schemas/Pet'
  /sample/pet:
    post:
      operationId: addPet
      requestBody:
        description: Pet object that needs to be added to the store
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Pet'
        required: true
      responses:
        default:
          description: default response
          content:
            application/json: {}
            application/xml: {}
components:
  schemas:
    Tag:
      type: object
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string
      xml:
        name: Tag
    Pet:
      type: object
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string
        tags:
          type: array
          xml:
            wrapped: true
          items:
            $ref: '#/components/schemas/Tag'
      xml:
        name: Pet

In this case resources are identified and provided to swagger-core engine by the swagger-jaxrs2-servlet-initializer; there are however several scenarios in which the dependency to swagger-jaxrs2-servlet-initializer is not necessary, as Swagger integration mechanism is capable of identifying resources from the ones configured by the JAX-RS environment, even without swagger specific settings (e.g. Application.getClasses(), resourcePackages Jersey init parameter, and more.

For example, adding io.swagger.v3.jaxrs2.integration.resources to Jersey 2 container servlet/filter jersey.config.server.provider.packages init param is by itself sufficient to integrate Swagger and have it scan and expose resolved spec. (in servlet-context-path/openapi.json or servlet-context-path/openapi.yaml).

Refer to Dependencies and Exposing OpenAPI definition for more details.

Resources configuration however, along with other init/config settings are fully configurable, see below and Integration and configuration.

Try it out by cloning/downloading the Jersey or RESTEasy sample, and running it with mvn package jetty:run OpenAPI definition will be available at http://localhost:8002/sample/openapi.yaml (and .json).

Not too bad so far, at this point we have a dynamic always-in-sync OpenAPI definition matching our application APIs, basically with zero code changes.

From here we might further customize our result by:

  1. Providing your own configuration (e.g resource packages/classes, output settings, etc.)
  2. Taking full control of your API definition (using Swagger annotations)

Or you can allow anyone — be it your development team or your end consumers — to visualize and interact with the API’s resources without having any of the implementation logic in place, using swagger-ui.

Skip to Integration and configuration for full configuration details and integration scenarios.

Your own configuration

There are several ways to provide configuration; probably the easiest and least intrusive way is adding a yaml (or json) file named openapi.yaml or openapi-configuration.yaml to the classpath of your application (location and path are flexible and configurable), e.g.

resourcePackages:
- io.swagger.sample.resource
prettyPrint: true
cacheTTL: 0
openAPI:
  info:
    version: '1.0'
    title: Swagger Pet Sample App Config File
    description: 'This is a sample server Petstore server.  You can find out more
      about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net,
      #swagger](http://swagger.io/irc/).  For this sample, you can use the api key
      `special-key` to test the authorization filters.'
    termsOfService: http://swagger.io/terms/
    contact:
      email: apiteam@swagger.io
    license:
      name: Apache 2.0
      url: http://www.apache.org/licenses/LICENSE-2.0.html

In the example above, we are providing the packages to be considered while resolving the definition (resourcePackages), we declare we want a pretty printed output (prettyPrint), we disable the cache to resolve the definition each time the endpoint is hit (cacheTTL), and we provide an info section directly in OpenAPI format, which will be merged with the resolved definition (openAPI).

In this case, as we are providing resourcePackages ourselves, there is no need to include the initializer dependency, therefore a single dependency on swagger-jaxrs2 is sufficient:

  <dependencies>
    ...
    <dependency>
      <groupId>io.swagger.core.v3</groupId>
      <artifactId>swagger-jaxrs2</artifactId>
      <version>2.0.0</version>
    </dependency>
  </dependencies>

Try it out by cloning/downloading the Jersey or RESTEasy sample, and running it with mvn package jetty:run OpenAPI definition will be available at http://localhost:8002/sample/openapi.yaml (and .json).

Full description of configuration properties is available here

Full control of your API definition

While Swagger resolver mechanism is able to analyze resource classes structure and various annotations (e.g JAX-RS, Jackson, etc.) there are cases where metadata is simply not available (for example determining the response schema of an operation, when the resource method is returning an instance of JAX-RS Responseinstead of a model POJO) and/or we want to completely customize the definition.

To handle this and other cases, and to be able to have full control over the resolved API definition, usage of Swagger annotations comes handy. Further customization can also be achieved by extension mechanisms.

Note: swagger-jaxrs2 reader engine includes by default also methods of scanned resources which are not annotated with @Operation, as long as a jax-rs @Path is defined at class and/or method level, together with the http method annotation (@GET, @POST, etc).

This behaviour is controlled by configuration property readAllResources which defaults to true. By setting this flag to false only Operation annotated methods are considered.

Let's slightly modify our simple resource:

@Path("/pet")
@Produces({"application/json", "application/xml"})
public class PetResource {
  static PetData petData = new PetData();

  @GET
  @Path("/{petId}")
  @Operation(summary = "Find pet by ID",
    tags = {"pets"},
    description = "Returns a pet when 0 < ID <= 10.  ID > 10 or nonintegers will simulate API error conditions",
    responses = {
            @ApiResponse(description = "The pet", content = @Content(
                    schema = @Schema(implementation = Pet.class)
            )),
            @ApiResponse(responseCode = "400", description = "Invalid ID supplied"),
            @ApiResponse(responseCode = "404", description = "Pet not found")
    })
  public Response getPetById(
      @Parameter(
              description = "ID of pet that needs to be fetched",
              schema = @Schema(
                      type = "integer",
                      format = "int64",
                      description = "param ID of pet that needs to be fetched",
                      allowableValues = {"1","2","3"}
              ),
              required = true)
      @PathParam("petId") Long petId) throws io.swagger.sample.exception.NotFoundException {
    Pet pet = petData.getPetById(petId);
    if (null != pet) {
      return Response.ok().entity(pet).build();
    } else {
      throw new io.swagger.sample.exception.NotFoundException(404, "Pet not found");
    }
  }
}

Here we explicitly declare responses for the operation, using @ApiResponse annotation; additionally we define operation tags and description and we provide a custom schema for a parameter.

The updated definition looks like:

...
paths:
  /sample/pet/{petId}:
    get:
      tags:
      - pets
      summary: Find pet by ID
      description: Returns a pet when 0 < ID <= 10.  ID > 10 or nonintegers will simulate
        API error conditions
      operationId: getPetById
      parameters:
      - name: petId
        in: path
        description: ID of pet that needs to be fetched
        required: true
        schema:
          type: integer
          description: param ID of pet that needs to be fetched
          format: int64
          enum:
          - 1
          - 2
          - 3
      responses:
        default:
          description: The pet
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
            application/xml:
              schema:
                $ref: '#/components/schemas/Pet'
        400:
          description: Invalid ID supplied
        404:
          description: Pet not found
...

We have been able to define a set of responses for the operation and customize a parameter schema, by adding related annotations. Annotations can be applied to resource classes and whatever model POJOs (particularly used in this context is the @Schema annotation).

Try it out by cloning/downloading the Jersey or RESTEasy sample, and running it with mvn package jetty:run OpenAPI definition will be available at http://localhost:8002/sample/openapi.yaml (and .json).

A Petstore sample exemplifies usage of all annotations

Full description of Swagger annotations is available here

Visualize and interact

Once an API definition is available, you might want to visualize it in a nice UI, and interact with it, for example testing the endpoint with an actual call. Such functionality is provided by swagger-ui which is nicely integratable with swagger-core

You can see how integration works by cloning/downloading the Jersey or RESTEasy sample (or most of samples), and running it with mvn package jetty:run Swagger UI will be available at http://localhost:8002.

The relevant code is the index.html file which makes use of swagger-ui bundle, downloaded and copied to resources in pom.xml: (while sample code downloades a new version from master report at every build, you can use whatever mechanism to obtain the bundle)

Dig deeper

For further scenarios, documentation and samples, check out Integration and configuration.

Clone this wiki locally