Guide - REST Style Guide

1 Introduction

This section contains a quick overview of conventions and rules that are outlined and discussed in more detail in the remaining sections of this document. Use this checklist whenever developing or reworking REST resources, resource objects, or clients.

Things you should do. Make sure:

  • your resource names fit the resource naming scheme
  • that every resource in your URI represents either a collection of other resources, or a "real" resource (an entity that is accessed and/or manipulated using HTTP methods)
  • you use (correct) HTTP status codes wherever possible
  • you use the (correct) HTTP methods only
  • you use standard (HTTP) methods of content-negotiation (e.g., headers  Accept and  Content-Type)
  • you use the base classes AbstractRestResourceAbstractRestCollectionResource, and  AbstractResourceObject to ensure consistency
  • your resource objects (ROs) are readable in JSON as well as XML format
  • to use human-readable, semantic IDs and names whenever possible
  • to use appropriate Authentication and Authorization mechanisms

Things you should not do:

  • Never use "meta" or "pseudo" resources
  • Never use method calls in the URI
  • Avoid introducing custom error responses
  • Never transform strings into object representations. Use  @Json... and  @Xml... annotations to define (de)serialization of your ROs.
  • Never rely on server state except for persistent information. (There is no session in REST!)

2 Further Reading

This document is only a style guide. It does not discuss the underlying principles more deeply .

Before beginning with the design and/or implementation of a REST API, resource, or resource object, you should read the following documents:

3 Resources 

3.1 Use 

Everything that is addressable via a URI in a REST API  has to be a resource, i.e., something representing a thing, or a concept, which can be retrieved and/or modified. REST APIs  do not expose  services(unlike SOAP WebServices).

All resources represent either a single resource, or a collection of resources. Method calls/identifiers as well as processing instructions (sorting, locale parameters, ...) are illegal in REST URIs except for query or matrix parameters.

3.2 Resource Naming

  • Resources should be named self-explanatory and human-readable (i.e., a list of products should be called products, not  prds).
  • Resources have to be named in English and the names are not localized.
  • Resource names should describe the resource, not just some aspect of it (i.e., a list of products should be called products, not  skus).
  • Single resources are always named using a singular noun.
  • Collections of resources are always named using a plural noun, preferably the plural of the name of the contained resources.
  • A resource's name is the only means of addressing it. Thus, it has to be locally unique within the containing resource. Names can be duplicated only at different paths, e.g., a product list resource occurring under multiple paths should be called products everywhere.
  • Elements of a collection resource are accessed by appending their key/name to the collection resource URI, i.e., a specific category is accessed via /categories/<categoryID>, not /categories/category/<categoryID>, as /category does not represent a resource itself.
  • If there is some anonymous default resource, the placeholder "-" is used (e.g., /users/- in the B2C REST API refers to the currently logged in user; a B2C user can only access his/her own data, and there is no need to know this ID just to address the sub-resource)

3.3 Sub-Resources vs. Resource Attributes

Use a sub-resource if the sub-resource:

  • represents a real, possibly independent, entity (e.g., something in a containment or association relation)
  • can be manipulated directly (e.g., items added or deleted)
  • needs to be addressed independently (e.g., as a reference)

Use an attribute if the attribute is :

  • only an aspect of the main resource (e.g., a characteristic, or a setting)
  • in a 0..1 relation to the main resource (e.g., a name, a price, a delivery state)

3.4 Resource Methods

All accessible objects (resources, collection resources, i.e., the subjects) are accessed only via URIs using standard HTTP methods (GET, POST, PUT, DELETE, OPTIONS, i.e., the verbs).

The following table gives a short overview of the most important actions. For more detail, see RFC 2616, Sec.9 .

Method

Purpose

CRUD equivalent

GET

Retrieves whatever information (in the form of an entity) is identified by the Request-URI. If the Request-URI refers to a data-producing process, it is the produced data which shall be returned as the entity in the response.

Read

POST

Requests that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line.

Create

PUT

Requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity should be considered as a modified version of the one residing on the origin server.

Update

DELETE

Requests that the origin server delete the resource identified by the Request-URI.

Delete

OPTIONS

Requests information about the communication options available on the request/response chain identified by the Request-URI.

 

Note

The methods POST and PUT are often confused since POST has been used for years to achieve the results of PUT on the web.

The fundamental difference between the POST and PUT requests is reflected in the different meaning of the Request-URI. The URI of a POST request identifies the resource that will handle the enclosed entity. That resource might be a data-accepting process, a gateway to some other protocol, or a separate entity that accepts annotations. In contrast, the URI in a PUT request identifies the entity enclosed with the request – the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource.

( RFC 2616, Sec.9.6 )

GET and HEAD are safe methods: They do not change anything on the server side. They can be called multiple times for the same URI and do not have any effects than returning (maybe) different values.

GET, HEAD, PUT, DELETE, OPTIONS, and TRACE are idempotent methods: They may have server side effects, but can still be called multiple times for the same resource without negative effects. For example, the same change to the same resource can be done multiple times; the state after that will be the same as after the first change (e.g., x=1 is the same as x=1;x=1;...;x=1). An HTTP PUT in Java corresponds to something like map.put(key, value) with the URI (or parts of it) being the key and the transferred data being the value.

In contrast, POST is a non-idempotent operation: In Java, it corresponds to something like list.add(value) with the transferred data being the value. It can have undesired effects when doing that multiple times.

If you feel you cannot adequately express the needed functionality with these methods, reconsider your resource structure. E.g., if you want to implement something like "add a new address for this user" and the user can have multiple addresses, you must not have a call like POST /users/myUser with an address, and you must not have a call like POST /users/myUser/addAddress?.... Instead, you should expose the addresses as a sub-resource, and manipulate that sub-resource with a call like  POST /users/myUser/addresses.

3.5 Security

In contrast to plain Jersey-based REST APIs, the Intershop REST framework enforces hierarchical access to the resources. This means, that the resource  addresses addressed via  /users/-/addresses can only be accessed if the parent resource  users can be accessed.

This allows any protection scheme to extend protection to all its sub-resources.

The user/client can send an authorization token, also in cases where no authentication is necessary (e.g. registration process).

3.6 Java

  • Resource classes should be named descriptively, i.e., UserListResource for the resource handling user listings,  UserResource for the resource handling the user data.
  • Resource classes should be about the client-facing side of the interface: Mapping requests to handling methods, and defining the response format.
  • Intershop-specific code, e.g., persistence-layer related code or pipeline calls, should be delegated to a specific class (by convention called  ...Handler, e.g., UserHandler).
  • Resource classes have to be derived from  AbstractRestResource or  AbstractRestCollectionResource.
  • Resource classes should use pre-defined responses wherever possible, i.e., use  RestExceptions, e.g., throw new RestException(RestException.ERROR_STATUS_NOT_FOUND); instead of setting response codes and headers manually).

4  Communication

As far as possible, the server should provide information / guidance to the client on how to send valid requests that achieve the intended results. Therefore, wherever possible use semantically fitting (pseudo-)standards (return codes as HTTP status codes, link relations as used by Atom etc.).

4.1 Content-Negotiation

The response format is chosen by the server in response to the client's HTTP Accept header (cf. RFC 2616, Sec.14 ).

Basically, this means that a client sending Accept: text/xml gets the response in XML format and a client sending Accept: application/json gets the response in JSON. If sending multiple values, the server selects its preferred of the supported formats.

If the server cannot provide the needed format, it returns the HTTP status code 406 automatically.

A format is supported if the resource handling of the request has the same annotated method as the handling of the used HTTP method and produces the requested content type:

@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
public ProductRO getProduct()

A resource class can provide any number of methods handling as many combinations of HTTP methods and  @Consumes and  @Produces annotations. 

4.2 Content Parametrization

To access specific representations of a resource, there are multiple ways:

  • use custom content types (i.e., the client can request application/json or a more specific version, e.g., application/json+vnd.intershop.someSpecificFormat)
    • use this to request a modified  format of the response
  • use query parameters (i.e., the client can request a default representation via  GET /products/123, a pre-defined view via GET /products/123?view=someViewID, or define his own view via  GET /products/123?attrs=sku,price,name; or the client can request only a subset of the returned data by searching or filtering the collection by a searchword)
    • use this to request a modified  content of the response
    • invalid parameters are be ignored

4.3 Response Status, Errors

When an error occurs, an appropriate HTTP status code (see W3C RFC2616 ) has to be returned. This can be achieved by manually calling addResponseData at the current resource or by simply throwing a RestException with the appropriate status code, message, and custom headers.

Do not use  200 OK with custom content for errors.

If additional data has to be transferred in a machine-readable way, custom HTTP response headers should be used, e.g.:

Status: 400 Bad Request (The attributes a,b,c are missing)
Headers:
  error-key: error.product.notification.attributes.missing
  error-type: error-missing-attributes
  error-missing-attributes: a,b,c

This allows the client to lookup the error message for the  error-key and display it. Also, it enables the client to process the missing attributes individually by parsing the comma-separated list error-missing-attributes, the key of which was transferred in the fixed header  error-type.

  • For  errors, use the appropriate builder method of class RestException to generate valid, consistent error responses (e.g., throw new RestException().notFound())
  • For  other results, use the appropriate method of class  RestResponseBuilder to generate valid, consistent responses (e.g., return getResponseBuilder().created(uri).build().

Examples for the use of these classes can be found in the Concept - REST Framework

 

For all operations,  use the appropriate HTTP status code to inform the client about the result of its call. The most important ones are the following: 

HTTP status code

Meaning

Description

Notes

200

OK

The request has succeeded.

Standard response code; generated automatically if no exception occurred.

201

Created

The request has been fulfilled and resulted in a new resource being created. The newly created resource can be referenced by the URI(s) returned in the entity of the response, with the most specific URI for the resource given by a location header field. The response should include an entity containing a list of resource characteristics and location(s) from which the user or user agent can choose the one most appropriate.

Header  Location is mandatory.

Return getResponseBuilder().created()

 

204

No content

The request has succeeded, but has no response data.

Return getResponseBuilder() .noContent()  

303

See other

The response to the request can be found under a different URI and should be retrieved using a GET method on that resource. This method exists primarily to allow the output of a POST-activated script to redirect the user agent to a selected resource. The new URI is not a substitute reference for the originally requested resource. The 303 response must not be cached, but the response to the second (redirected) request may be cacheable. The different URI should be given by the location field in the response. Unless the request method was HEAD, the entity of the response should contain a short hypertext note with a hyperlink to the new URI(s).

Return getResponseBuilder().seeOther()

400

Bad Request

The request could not be understood by the server due to malformed syntax. The client should not repeat the request without modifications. 

Use if required content is missing or invalid. Do not use when just a wrong query parameter was sent.

For most cases, throw new RestException().missingAttributes() or new RestException().invalidAttributes().

401

Unauthorized

The request requires user authentication. The response must include a WWW-Authenticate header field ( section 14.47 ) containing a challenge applicable to the requested resource. The client may repeat the request with a suitable Authorization header field ( section 14.8 ). If the request already included authorization credentials, then the 401 response indicates that authorization has been refused for those credentials.

Handled by  AuthorizationProvider

403

Forbidden

The server understood the request, but is refusing to fulfill it. Authorization will not help and the request should not be repeated.

Used if the user is known (i.e., authenticated), but not allowed access (i.e., not authorized)

404

Not found

The server has not found anything matching the Request-URI. No indication is given of whether the condition is temporary or permanent. This status code is commonly used when the server does not wish to reveal exactly why the request has been refused, or when no other response is applicable.

Use only if no  resource could be found at this URI.  Do not use it if the resource was found but couldn't return any date (e.g., a search without results).

Throw  new RestException().notFound().

405

Method not allowed

The method specified in the Request-Line is not allowed for the resource identified by the Request-URI. The response must include an Allow header containing a list of valid methods for the requested resource.

The framework generates this status and the corresponding "allow" header.

406

Not acceptable

The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request. 
Unless it was a HEAD request, the response should include an entity containing a list of available entity characteristics and location(s) from which the user or user agent can choose the one most appropriate. The entity format is specified by the media type given in the Content-Type header field.

Use only if the requested content type cannot be provided. Automatically generated.

409

Conflict

The request could not be completed due to a conflict with the current state of the resource. This code is only allowed in situations where it is expected that the user may be able to resolve the conflict and resubmit the request. The response body should include enough information for the user to recognize the source of the conflict. Ideally, the response entity includes enough information for the user or user agent to fix the problem; however, this may not be possible and is not required. Conflicts are most likely to occur in response to a PUT request.

Throw  new RestException().conflict().

500

Internal Server Error

The server encountered an unexpected condition which prevented it from fulfilling the request.

Thrown automatically when uncaught exception occurs.

Do  not use for foreseeable errors!

In addition, operations may have specific status codes.

 

There are some standard status code and header combinations following directly from the above table:

MethodActionCodeHeaderBody
GET uriRetrieve representation200 (OK)-Representation of item
POST uriAdd new item as sub-resource of uri201 (Created)LocationLinkRO
 If the creation updated more than just this item, send "See other"303 (See Other)LocationLinkRO
PUT uriUpdate the item at uri200 (OK) Updated representation of item
 If the creation updated more than just this item, send "See other"303 (See Other)LocationLinkRO
DELETEDelete the item at uri204 (No Content)--
 If the creation updated more than just this item, send "See other"303 (See Other)LocationLinkRO

The status codes for authentication and permission issues are usually generated automatically, as are the status codes 405 and 406.

5 Resource Objects

5.1 Use

Recource objects (RO) are the standard means of data exchange. They are just  data containers without logic.

Their serialization is controlled using Jackson annotations like  @JsonProperty and Jackson-Jaxb annotations like  @XmlElement.

An RO exposes all intended properties. It needs to have getters and setters to allow for JSON and XML (de)serialization.

However, an RO having a setter for a property does not mean that the property can be set from the outside! It only means that the property will be deserialized. Server-side logic (in the resource class handling the RO input) then decides whether or not to use that information. Therefore, do not introduce custom ROs just to prevent input!

There should only be as many types of ROs as necessary.  Do not add ROs just to represent different views on the same resource. The client should be able to understand a set of ROs relevant for its purpose, and not encounter new ROs all the time.

5.2 Resource Object Types 

All resource objects should be derived from  AbstractResourceObject or  ExtensibleResourceObject. This makes sure that serialization and deserialization are handled consistently.

These base classes are Jackson-annotated to expose only public fields and getters/setters. All other fields and methods which should be exposed have to be annotated with @JsonProperty or  @XmlElement@XmlAttribute. Values which resolve to  null are not serialized. This behavior is inherited by all sub-classes.

As a result, a typical RO can be a plain old Java object (POJO) extending AbstractResourceObject

Serialization is configured to use the  type attribute of an RO when (de)serializing. The  type is automatically included in the JSON representation as "type":"MyObject" and in XML as  <MyObject name="someName" type="MyObject">.

Note: In XML, the tag name will be set to the type only for anonymous objects (e.g., elements of a list). If an RO is set as an attribute value on some other RO, the tag name will be the name of the attribute.

The  type should be set to the name of the RO without the suffix "RO", i.e., the type of the  ProductRO should be  Product.

5.3 Naming

The name of the resource object should describe the object, so that it is understandable to both the server-side developer and the client-developer. It should end in the suffix "RO". I.e., an RO representing a Product should be named "ProductRO".

If your RO's name includes semantics other than the described object, it should be examined critically. E.g., when encountering ROs named NewCustomerRO, re-evaluate the need for that representation. Does the  NewCustomerRO describe an object different from  CustomerRO? In what respect? If it just exists to add more attributes and setters/getters, it should be removed (see section Guide - REST Style Guide#Use). 

5.4 LinkRO 

As REST APIs typically need to return links to resources (e.g., in an item listing), the framework provides a simple class for this purpose.
The LinkRO has the following attributes:

  • uri: the address of the linked resource 
  • title: as the links have to be consumed and possibly displayed on the client side, a title can be set to show to the user
  • description: as the links have to be consumed and possibly displayed on the client side, a description can be set to show to the user 
  • relation: an optional attribute describing the relation of the linked object to the current resource
  • name : (inherited from  AbstractResourceObject)

To enhance the  LinkRO, it can also contain additional attributes. Be careful, do not to return too many attributes here. Return only those attributes that are necessary for the client when choosing one of the links to follow. For a product link, this can be the price, the availability, or a thumbnail, but usually not the high-definition product image.

5.5 ResourceCollectionRO 

The  ResourceCollectionRO is a typed ordered list of ROs. In addition, it has properties for paging and sorting information (although such functionality is not provided by the class itself).

The ResourceCollectionRO should only be used as a direct response to a request (i.e., as a top-level data type). E.g., a  GET /someResource could return a  ResourceCollectionRO, but a  someRO should not have an attribute of type  ResourceCollectionRO. It introduces an unnecessary hierarchy-level (with the attribute elements) and is harder to (de)serialize.

Background: The ResourceCollectionRO only exists to provide access to enhanced list information/options, such as pageable, total, offset, etc. These options can only be accessed when the resource itself is reachable via a URI. Because of that, it makes no sense to use this data-type for enclosed lists which are only reachable via another items attributes and cannot be parametrized. 

6 Documentation

  • All resource classes have to be programmed and documented using the Java Source Code Style Guide
  • All web-facing methods of a resource class (i.e., anything annotated with  @GET@POST@PUT@DELETE, or  @OPTIONS need to be well-documented.
  • Resource objects can be less thoroughly documented, because they are mere containers and already need to have descriptive names for methods and attributes.

 

 

Disclaimer

The information provided in the Knowledge Base may not be applicable to all systems and situations. Intershop Communications will not be liable to any party for any direct or indirect damages resulting from the use of the Customer Support section of the Intershop Corporate Web site, including, without limitation, any lost profits, business interruption, loss of programs or other data on your information handling system.

Customer Support
Knowledge Base
Product Resources
Support Tickets