About

Fathom-REST-Swagger integrates Fathom-REST with Swagger to provide you with an easy to use RESTful API specification generator and browser.

Note

The Swagger specification is quite detailed. Fathom-REST-Swagger makes a best-effort to provide an excellent Swagger experience, but it does not support all aspects of the specification.

Installation

Add the Fathom-REST-Swagger artifact.

<dependency>
    <groupId>com.gitblit.fathom</groupId>
    <artifactId>fathom-rest-swagger</artifactId>
    <version>${fathom.version}</version>
</dependency>

Layout

YourApp
└── src
    └── main
        ├── java
        │   └── controllers
        │       ├── EmployeeController.java
        │       └── ItemController.java
        └── resources
            └── swagger
                ├── info.md
                └── controllers
                    ├── EmployeeController
                    │   ├── getEmployee.md
                    │   └── deleteEmployee.md
                    └── ItemController
                        ├── getItem.md
                        └── deleteItem.md

Configuration

Fathom-REST-Swagger is configured in your resource config file conf/default.conf.

swagger {

  # The host (name or ip) serving the API.  This MUST be the host only and does
  # not include the scheme nor subpath.  It MAY include a port. If the host is
  # not specified, the host serving the documentation is to be used
  # (including the port).
  host = ""

  # The base path on which the API is served, which is relative to the host.
  # All specified routes will be relative to this path.
  basePath = "/api"

  # The transfer protocol of the API.
  schemes = [ "http", "https" ]

  # Swagger API Specification
  info {
    # Title of your API
    title = "Example API"

    # Markdown API description resource to load and insert into the generated specification
    description = "classpath:swagger/info.md"

    # API version to display in your generated specifications
    # The default is your {application.version}.
    version = "1.0.0"

    # API Contact Information
    contact {
      name = "API Support"
      url = "http://www.swagger.io/support"
      email = "support@swagger.io"
    }

    # API License Information
    license {
      name = "The Apache Software License, Version 2.0"
      url = "http://www.apache.org/licenses/LICENSE-2.0.txt"
    }
  }

  # External documentation link
  externalDocs {
    url = "http://swagger.io"
    description = "More about Swagger"
  }

  # Swagger UI and Specification Serving
  ui {
    # Path for serving Swagger UI and Swagger specifications
    # This path is relative to your application, not swagger.basePath
    #  - Swagger UI served on /{swagger.ui.path}
    #  - JSON specification served on /{swagger.ui.path}/swagger.json
    #  - YAML specification served on /{swagger.ui.path}/swagger.yaml
    path = "/api"

    # Path to the Swagger UI template, relative to the templates resource directory.
    # Fathom-REST-Swagger ships with the standard Swagger UI template for Pebble,
    # Freemarker, and Trimou, although you may wish to customize this template.
    template = "swagger/index"

    # Text to display in the banner of the Swagger UI
    bannerText = "swagger"

    # Define the name of the token to send from Swagger UI.
    # The default value is "api_key"
    apiKeyName = api_key

    # Define the type of the API key to send from Swagger UI.
    # The default type is "header", the alternatives are "query" and "none".
    apiKeyType = header

    # Display the API key text field in Swagger UI.
    # Showing the text field allows the api key to be manually specified.
    hideApiKey = true

  }

}

Usage

Fathom-REST-Swagger registers a service which will automatically generate & serve Swagger 2.0 specifications in JSON and YAML. The specifications are generated from your registered Fathom controller routes at runtime. Routes that are directly implemented in the conf/Routes.java class are not considered for inclusion because they lack too much detail.

Note

Only RESTful Fathom Controller Routes are included in the generated Swagger specifications.

RESTful Fathom Controller Routes

A RESTful web API is an http/https service that processes resource requests (/employee/5) using http verbs (GET, POST, PUT, DELETE, etc).

RESTful web APIs typically…

  • Produce application/json, application/xml, application/x-yaml, text/plain
    and
  • Consume application/json, application/xml, application/x-yaml, text/plain, application/x-www-form-urlencoded, and/or multipart/form-data

In order for a Fathom controller route to be registered in your Swagger specification…

  1. the route must declare that it @Produces one or more of the aforementioned content-types
  2. the route must declare one of the following http verbs: @GET, @POST, @PUT, @PATCH, @DELETE, @OPTIONS
  3. the route must declare at least one @Return specification
  4. the route and it’s declaring controller are NOT annotated with @Undocumented
  5. the route’s uri pattern must begin with the configured swagger.basePath
// Controller API Method, REGISTERED in Swagger specification
@GET("/employee/{id}")
@Produces({Produces.JSON, Produces.XML})
public Employee getEmployee(int id) {
}

// Controller View Method, NOT REGISTERED in Swagger specification
@GET("/employee/{id}.html")
@Produces({Produces.HTML})
public void getEmployee(int id) {
}

Improving the Generated Specification

Fathom-REST-Swagger is able to generate a fairly complete Swagger specification from your modestly-documented or well-documented Fathom-REST controllers.

However, there is always room for improvement. Your generated specification, while functional, can not fully showcase your API without some hints from you.

@ApiOperations

You may use the @ApiOperations annotation to briefly describe a controller and it’s set of methods. In Swagger, operations are grouped together by their tag and those operations usually share a common base path (e.g. /api/employee). You may optionally localize the @ApiOperations description.

@Path("/api/employee")
@Produces({Produces.JSON, Produces.XML})
@ApiOperations(tag="employees", description="Employees API", descriptionKey="api.description.employees")
public class EmployeeController extends Controller {
}

@Named and/or @ApiSummary

You may name your controller routes using the @Named annotation. This information is used in the Summary field of the Swagger specification and may also be used for normal runtime logging of route dispatching. Alternatively, you may use the @ApiSummary annotation which is only used as the summary in your generated Swagger specification. You may optionally localize @ApiSummary.

@GET("/{id}")
@Named("GetEmployeeById")
@ApiSummary(value="Get employee by id", key="api.employee.getById")
public Employee getEmployee(int id) {
  Employee employee = employeeDao.get(id);
  return employee;
}

Note

The @Named annotation is part of Fathom-REST and is re-used for Swagger.

@ApiNotes

The @ApiNotes annotation adds a brief description to an operation in addition to the @Named or @ApiSummary (Summary) information. You may optionally localize @ApiNotes.

You can use @ApiNotes to load a classpath resource notes file. GFM syntax may be used.
These two examples are equivalent for a given controller method.

@GET("/{id}")
@ApiNotes
public Employee getEmployee(int id) {
  Employee employee = employeeDao.get(id);
  return employee;
}

@GET("/{id}")
@ApiNotes("classpath:swagger/com/package/EmployeeController/getEmployee.md")
public Employee getEmployee(int id) {
  Employee employee = employeeDao.get(id);
  return employee;
}

Or you may directly specify your note text with an optional translation:

@ApiNotes(value="This method requires a **valid** employee id", key="api.notes.getEmployeeById")
public Employee getEmployee(int id) {
  Employee employee = employeeDao.get(id);
  return employee;
}

@Desc

You may use the @Desc annotation to briefly describe a controller method parameter. You may optionally localize @Desc.

@GET("/{id}")
public Employee getEmployee(@Desc("employee id") int id) {
  Employee employee = employeeDao.get(id);
  return employee;
}

@DELETE("/{id}")
public Employee deleteEmployee(@Desc(key="api.employee.idParameter") int id) {
}

@Form

Specify the @Form annotation to indicate that a method argument is sourced from a form.

@POST("/{id}/uploadAvatar")
public void uploadAvatar(
    @Desc("employee id") int id
    @Desc("nickname") @Form String nickname,
    @Desc("avatar to upload") @Form FileItem avatar) {

}

@Return

You may use the @Return annotation to briefly describe method-specific responses.

@GET("/{id}")
@Return(code = 200, description = "Employee retrieved", onResult = Employee.class)
@Return(code = 404, description = "Employee not found", onResult = Void.class)
public Employee getEmployee(@Desc("employee id") int id) {
  Employee employee = employeeDao.get(id);
  return employee;
}

Note

The @Return annotation is part of Fathom-REST and is more thoroughly documented in that module.

@RequireToken

You may use the @RequireToken annotation to enforce token-based authentication for your controller method.

@GET("/{id}")
@RequireToken
public Employee getEmployee(@Desc("employee id") int id) {
  Employee employee = employeeDao.get(id);
  return employee;
}

Note

The @RequireToken annotation is part of Fathom-REST-Security and is more thoroughly documented in that module.

CORS or Cross Origin Resource Sharing

CORS is a technique to prevent websites from doing bad things with your personal data. Most browsers + javascript toolkits not only support CORS but enforce it, which has implications for your API server which supports Swagger.

You can read about CORS here: http://www.html5rocks.com/en/tutorials/cors/.

There are two cases where no action is needed for CORS support:

  1. swagger-ui is hosted on the same server as the application itself (same host and port).
  2. The application is located behind a proxy that enables the requires CORS headers. This may already be covered within your organization.

Otherwise, CORS support needs to be enabled for:

  1. Your generated Swagger specifications, swagger.json and swagger.yaml
  2. Your API endpoints, if you want the Try it now button to work

Configuring CORS Support

Add a HeaderFilter in your conf/Routes.java class before you register your API routes.

CORSFilter corsFilter = new CORSFilter();
corsFilter.setAllowOrigin("*");
corsFilter.setAllowMethods("GET", "POST", "PUT", "PATCH", "DELETE", "HEAD");
corsFilter.setAllowHeaders("Content-Type", "api_key", "Authorization", "Csrf-Token");

ALL("/api/?.*", corsFilter).named("CORS Filter");

Testing CORS Support

Once you have setup your CORS filter, you can test that the appropriate headers are being set with curl or your favorite browser extension.

$ curl -v -X OPTIONS --header "Access-Control-Request-Method: GET" "http://localhost:8080/api/swagger.json"
* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> OPTIONS /api/swagger.json HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost:8080
> Accept: */*
> Access-Control-Request-Method: GET
>
< HTTP/1.1 200 OK
< Connection: keep-alive
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Headers: Content-Type,api_key,Authorization,Csrf-Token
< Content-Type: text/html;charset=UTF-8
< Content-Length: 0
< Access-Control-Allow-Methods: GET,POST,PUT,PATCH,DELETE,HEAD
< Date: Thu, 18 Jun 2015 22:06:47 GMT
<
* Connection #0 to host localhost left intact