REST

Goals

Concepts

Lesson

The early World Wide Web for many years consisted mainly of the transfer of resources (such as web pages; text documents; images, and audio files) using HTTP as the transfer protocol. As the web evolved users wanted to invoke actions remotely (such as making bank transfers or ordering new stock). Developers wanted to transfer the type of functionality normally found in the service layer to a remote server.

Initially in order to access these remote services, many developers invented proprietary protocols that communicated in arcane codes at the application level of TCP/IP. Many times these protocols used remote procedure calls (RPC), sometimes referred to as remote method invocation (RMI), with which a developer could call a method locally and it would be executed on a remote system. Such protocols required new libraries to be created, were difficult to use, and moreover were blocked by many firewalls.

A step forward came when Microsoft invented the Simple Object Access Protocol (SOAP), which later was standardized by the W3C. SOAP provided an XML-based wrapper for general messages to be transported across the Internet. By using an existing protocol such as HTTP as its transport mechanism, it avoided problems with firewalls. SOAP was very general; each use case would need a specific SOAP-compliant message content, although SOAP defined some standard types. Even though SOAP comprised a general message format and unified type system, in some ways it was just a glorified protocol for remote procedure invocation.

REST

In the year 2000 Roy T. Felding pointed out that access to remote services do not need an additional protocol on top of HTTP. Instead the existing architecture of the World Wide Web provides a sufficient model on which to perform remote actions using HTTP itself. This approach to web services is not a set of rules but rather an overarching philosophy to web API design known at representational state transfer (REST).

There are several core themes in a REST-based approach to web services, or RESTful API:

HTTP-based RESTful APIs have many benefits over the earlier RPC-oriented approaches. Besides being able to navigate firewalls, they lower the ramp-up time by allowing developers to leverage existing HTTP libraries, getting additional capabilities such as authentication built into the protocol.

Resource URIs

REST views its subject matter as resources. These may be concrete resources such as documents or abstract resources such as customers or bank accounts. As you know from the lesson on Internet protocols, the existing architecture of the web already uses URIs to identify resources. A typical RESTful API will indicate some base URI under which all its resources will appear. A RESTful API for managing a farm, for example, might use the base URI http://example.com/farm/.

Types of resources are usually described by URI collection resources ending with the slash / character:

Retrieving one of these resource endpoints will provide some representation of the resources within that category. For example, an HTTP GET for http://example.com/farm/pens/ might return the following JSON document:

JSON response to GET http://example.com/farm/pens/.
[
  {"id": "pigpen", "name": "Pig Pen", "uri": "http://example.com/farm/pens/pigpen"},
  {"id": "backyard", "name": "Back yard", "uri": "http://example.com/farm/pens/backyard"},
  {"id": "field1", "name": "Little Field", "uri": "http://example.com/farm/pens/field1"},
  {"id": "field2", "name": "Big Field", "uri": "http://example.com/farm/pens/field2"},
]

Note carefully that REST considers the URI http://example.com/farm/pens/ to be a resource—specifically a list of pens. In the REST paradigm you are not asking the server to generate a list. Rather you consider the list as something that exists and can be identified, and you tell the server that you want to GET it.

Retrieving a representation of the pig pen resource is thereafter only a merely a matter of issuing an HTTP GET to http://example.com/farm/pens/pigpen, which might return the following JSON response:

JSON response to GET http://example.com/farm/pens/pigpen.
{
  "id": "pigpen",
  "name": "Pig Pen",
  "uri": "http://example.com/farm/pens/pigpen",
  "width": "30",
  "length": "40",
  "capacity": "100"
}

URI Queries

The query part of a URI provides an ideal place to indicate a specific aspect or portion of the resource to be returned. When retrieving the resource at the URI http://example.com/farm/pens/, for example, a minCapacity query parameter might specify that only pens with some minimum capacity be included in the returned list. A query parameter of limit might indicate the maximum number of entries to include in the list.

Example query parameters for GET http://example.com/farm/pens/.
http://example.com/farm/pens/?minCapacity=80&limit=5
minCapacity
Filters out pens with lower capacity.
limit
Indicates the maximum number of pens to return.

HTTP Methods

The existing HTTP methods provide ample capabilities for working with the resources modeling your subject domain. Here are some of the common HTTP methods you will use, along with appropriate headers and responses.

Common HTTP Methods Used with REST
Method Description Headers Response
GET Requests transfer of a representation of a resource. Idempotent. Safe.
  • Accept
200 (OK)
The resource was found and returned.
404 (Not Found)
No such resource was found.
HEAD Requests transfer of the headers related to a resource. Functions virtually identical to GET except that no content is returned in the HTTP response. Idempotent. Safe.
  • Accept
200 (OK)
The resource was located.
404 (Not Found)
No such resource was found.
PUT Requests that the state of the target resource be created or replaced. Idempotent.
200 (OK)
Existing resource was replaced; new resource returned.
201 (Created)
Resource is new.
204 (No Content)
Existing resource was successfully replaced; no resource returned.
404 (Not Found)
If resource does not exist and API does not allow creation via this endpoint.
PATCH Requests that a portion of the resource representation be updated. Currently uses some proprietary representation of a portion of a resource. Not yet widely used.
200 (OK)
Successful update; modified resource returned.
204 (No Content)
Successful update.
DELETE Requests that the target resource be removed from the server. Idempotent. Just because DELETE is idempotent doesn't mean a different response code can't be returned based upon whether the resource existed before the call. See Does idempotency include response codes?
200 (OK)
Successful deletion; deleted resource returned.
202 (Accepted)
Successful deletion request but not yet enacted.
204 (No Content)
Successful deletion.
404 (Not Found)
Resource does not exist and therefore cannot be deleted.
POST Requests that the resource process the contents of the request. Allows substantial liberty in which information is passed and how that information is used. Originally used to process the response of HTML form submissions. It can be tempting to use the POST method as a way to sneak in RPC.
200 (OK)
Existing resource was replaced; new resource returned.
201 (Created)
Resource is new.
204 (No Content)
Existing resource was successfully replaced; no resource returned.
404 (Not Found)
If resource does not exist and API does not allow creation via this endpoint.

Content Negotiation

One of the most beneficial aspects of HTTP used for REST is the ability for make available several representations of the same resource. Through content negotiation, the user agent can tell the client which media type it prefers. One user agent may prefer to process a list of resources in JSON, while another may prefer a plain text list, or an XML document.

HTTP specifies a preferred media type by using the Accept header in the GET or HEAD request. The media type(s) indicated in the Accept request header are the same as may be returned in the Content-Type response header. The Accept header may provide an additional q quality factor parameter to indicate the relative degree of preference for that media type.

Simple content negotiation.
Accept: application/json
Complex content negotiation with relative preference indicated.
Accept: application/json;q=0.8, text/xml; q=0.5; text/*

OpenAPI

Just like interfaces in Java, a RESTful API is a contract of how distributed system modules talk to each other—what input is expected and what response is promised. REST usually uses HTTP and could be implemented by virtually any programming language. There are no HTTP method signatures like Java has to communicate to other modules which methods can be called along with their parameters. Ad-hoc documentation is one way to communicate to developers what REST endpoints are available and how they are used, but this sort of documentation tends to be inconsistent and incomplete.

Several efforts have attempted to create a common language for RESTful API documentation—essentially a Javadocs for REST—that is machine-readable but can also produce attractive documentation for human consumption. Although they are other popular alternatives, including the RESTful API Modeling Language (RAML) and API Blueprint specifications, this lesson will concentrate on the OpenAPI . Previously named Swagger, the OpenAPI 2.0 specification is the most popular approach for documenting RESTful APIs.

Specification File

API documentation that uses OpenAPI 2.0 is placed in a specification file written in JSON and using certain fields that have special meaning. OpenAPI considers the API being documented to be an application in itself. There are several fields that should be in the root object of the specification file, which is usually named swagger.json:

Root Swagger specification JSON object fields.
"swagger"
Must be set to "2.0". Required.
"info"
Provides metadata about the API. Required.
"title"
The title of the application. Required.
"description"
A longer description of the application.
"version"
The version of the API. Required.
"basePath"
The path, starting with a slash / character, that is the base of the API endpoints. This path should not end with a slash / character, even though it is a base path.
"paths:
Lists and describes the REST endpoints. Required.
Minimal swagger.json for Farm API.
{
  "swagger": "2.0",
  "info": {
    "title": "Farm API",
    "description": "Manage your farm using REST.",
    "version": "0.1.0"
  },
  "basePath": "/farm",
  "paths": {}
}

The paths field provides a description for each of the RESTful API endpoints. These paths also start with the slash / character, and are considered relative to the basePath. This is analogous to how Java servlet paths are interpreted relative to the servlet context path. For each path, the associated JSON object will have a field for each HTTP method support, in lowercase, such as "get" or "put". Each method in turn will be associated with an object describing that operation.

Swagger specification operation description JSON object fields.
"summary"
A short summary of the operation.
"description"
A longer description of the operation.
"tags"
A list of string categories for grouping similar operations.
"parameters"
A list of any parameters, each a separate JSON object:
"name"
The name of the parameter. Required. TODO case sensitive
"in"
Indicates the location ("query", "header", "path", "formData", or "body") of the parameter. Required.
"description"
A brief desription of the parameter.
"type"
The type ("string", "number", "integer", "boolean", "array" or "file") of parameter value. Required if "in" is not set to "body".
"required"
Indicates whether the parameter is mandatory (true or false). Required to be true if "in" is set to "path".
"consumes"
A list of media types consumed by the operation.
"produces"
A list of media types produced by the operation.
"responses"
An object describing the HTTPrespons codes that could be returned, each a separate JSON object. Required.
description
A short description of the response. Required.
schema
TODO
"headers"
A description of headers sent with the response. TODO complete
"examples"
TODO
swagger.json with path descriptions for Farm API
{
  "swagger": "2.0",
  "info": {
    "title": "Farm API",
    "description": "Manage your farm in a RESTful way.",
    "version": "0.1.0"
  },
  "host": "foobar",
  "basePath": "/farm",
  "paths": {
    "/pens/": {
      "get": {
        "description": "Retrieves a list of available pens.",
        "tags": ["pens"],
        "parameters": [{
          "name": "minCapacity",
          "in": "query",
          "description": "The minimum capacity of a pen to return.",
          "type": "integer",
          "required": false
        }, {
          "name": "limit",
          "in": "query",
          "description": "The maximum number of pens to return.",
          "type": "integer",
          "required": false
        }],
        "produces": ["application/json"],
        "responses": {
          "200": {
            "description": "Pen list."
          }
        }
      },
      "post": {
        "description": "Adds a new pen.",
        "tags": ["pens"],
        "consumes": ["application/json"],
        "produces": ["application/json"],
        "responses": {
          "201": {
            "description": "New pen created."
          }
        }
      }
    },
    "/pens/{penId}": {
      "get": {
        "description": "Retrieves an individual pen.",
        "tags": ["pens"],
        "parameters": [{
          "name": "penId",
          "in": "path",
          "description": "Identifies the pen to retrieve.",
          "type": "string",
          "required": true
        }],
        "produces": ["application/json"],
        "responses": {
          "200": {
            "description": "Pen"
          },
          "404": {
            "description": "Pen not found."
          }
        }
      },
      "put": {
        "description": "Updates a pen.",
        "tags": ["pens"],
        "parameters": [{
          "name": "penId",
          "in": "path",
          "description": "Identifies the pen to update.",
          "type": "string",
          "required": true
        }],
        "consumes": ["application/json"],
        "produces": ["application/json"],
        "responses": {
          "204": {
            "description": "Pen updated."
          },
          "404": {
            "description": "Existing pen not found."
          }
        }
      },
      "delete": {
        "description": "Deletes a single pen.",
        "tags": ["pens"],
        "parameters": [{
          "name": "penId",
          "in": "path",
          "description": "Identifies the pen to delete.",
          "type": "string",
          "required": true
        }],
        "responses": {
          "204": {
            "description": "Pen deleted."
          },
          "404": {
            "description": "Pen does not exist."
          }
        }
      }
    }
  }
}

Swagger UI

The Swagger UI project is a platform for producing interactive HTML documentation from your Swagger specification file. It comes with an HTML web page containing static JavaScript and CSS files that be served as a self-contained web site. Simply deploy the Swagger URI files in a separate directory, include your swagger.json file, and edit a line of JavaScript in the main HTML file to reference your swagger.json file.

  1. Download the latest Swagger UI source code archive from the Swagger UI Releases page.
  2. From the archive file extract to the dist/ subdirectory to the location you want the documentation to appear. You can rename the directory if you wish. If you want this served from your web application, place it in the Maven src/main/webapp/ directory (explained below).
  3. Place your swagger.json file in the root of this directory.
  4. Edit the index.html file found in the root of this directory, changing the SwaggerUi constructor argument url to link to your local swagger.json file, as shown in the figure.
dist/index.html modified to link to swagger.json file.
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Swagger UI</title>
  …
  <script type="text/javascript">
    $(function () {
      …
      window.swaggerUi = new SwaggerUi({
        url: "swagger.json",
        dom_id: "swagger-ui-container",
        …

Web Application Static Content

Java web applications allow static content to be included and served directly to clients, as long as the files are included outside the /WEB-INF directory. Maven provides the src/main/webapp directory as part of its standard directory layout for this purpose. Any files and/or directories included in src/main/webapp will be included in the the resulting WAR file when the project is built. Tomcat can automatically serve static content from a WAR file, and even recognizes the index.html file as the default file to return for a directory.

Review

Gotchas

In the Real World

Think About It

Self Evaluation

Task

Design and document a RESTful API for Booker web services. Your API will be accessible at the base path /booker/api/ on your server.

Your initial Booker servlets serving /booker/application will become part of your Booker RESTful API.

Design RESTful web service functionality equivalent to that available in the Booker PublicationRepository interface.

Deploy your updated web application project, which will now include your RESTful API documentation, to your server.

See Also

References

Resources