REST
Goals
- Understand the core concepts of REST.
- Know how to design a RESTful API.
- Learn how to document a RESTful API using OpenAPI .
Concepts
- API Blueprint
- endpoint
- Hypermedia as the Engine of Application State (HATEOAS)
- OpenAPI
- pagination
- remote method invocation (RMI)
- remote procedure calls (RPC)
- representational state transfer (REST)
- resource
- RESTful API
- RESTful API Modeling Language (RAML)
- Simple Object Access Protocol (SOAP)
- Swagger
- web services
- YAML
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:
- The subject matter is viewed as a representations of resources identified by URIs.
- The commands of an existing protocol (usually HTTP) are used to change the states of those resources.
- Hyperlinks are used to connect the resources.
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:
http://example.com/farm/animals/
http://example.com/farm/barns/
http://example.com/farm/pens/
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:
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
it.GET
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:
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.
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.
Method | Description | Headers | Response |
---|---|---|---|
GET | Requests transfer of a representation of a resource. Idempotent. Safe. |
|
|
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. |
|
|
PUT | Requests that the state of the target resource be created or replaced. Idempotent. |
| |
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. |
| |
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? |
| |
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. |
|
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.
Accept: application/json
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
:
"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.
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.
"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
orfalse
). Required to betrue
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.
- Download the latest Swagger UI source code archive from the Swagger UI Releases page.
- 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 Mavensrc/main/webapp/
directory (explained below). - Place your
swagger.json
file in the root of this directory. - Edit the
index.html
file found in the root of this directory, changing theSwaggerUi
constructor argumenturl
to link to your localswagger.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
- Do not user a verb in the URI of your URI endpoint; the HTTP method is the verb.
- Do not misuse the
POST
method as a way to sneak in RPC. - Don't simulate HTTP content negotiation by using different filename extensions to indicate different content types.
- Use HTTP error codes to indicate errors; don't use special, proprietary headers of content.
In the Real World
- Beware that many APIs you will encounter in real life may use the name
REST
simply because they use HTTP as a transport mechanism, even though they don't follow REST philosophy. These APIs have a higher learning curving and lower interoperability with other tools.
Think About It
- Do the objects in your domain contain identifiers as part of their resource representation? Is there a way for a developer to know the ID of a resource before it is created? If so, do you want to allow creation via a
PUT
to some endpointfoobars/foobarId
, or will you nevertheless require aPOST
to endpointfoobars/
?
Self Evaluation
- TODO
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.
- This REST endpoint will identify that the client indeed accessing the Booker API.
- Change your
@WebServlet
paths so that this endpoint is mounted at/booker/api/application
(and likewise for/booker/api/app
).
Design RESTful web service functionality equivalent to that available in the Booker PublicationRepository
interface.
- Use OpenAPI to document your RESTful API, using
/booker/api
as the API base path. Don't forget to document the/booker/api/application
endpoint. - Use Swagger UI to provide web-based, browsable documentation at
/booker/api-doc/
. - Store your documentation as a swagger.json file in the root of your Swagger UI directory in your project.
Deploy your updated web application project, which will now include your RESTful API documentation, to your server.
See Also
- Best Practices for Designing a Pragmatic RESTful API (Vinay Sahni)
- Idempotency in Cows and REST APIs (YouTube - restapitutorial)
- Writing OpenAPI (Swagger) Specification Tutorial – Part 1 – Introduction (API Handyman)
References
- Principled design of the modern Web architecture, ACM Transactions on Internet Technology, 2, 2, pp. 115-150 (May 2002), doi:10.1145/337180.337228 (Roy T. Fielding, Richard N. Taylor)
- RFC 5789: PATCH Method for HTTP
- RFC 6570: URI Template
- RFC 7230: Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing
- RFC 7231: Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content
- HTTP Decision Diagram
- OpenAPI Specification, Version 2.0