How should REST services be documented?

5 minute read

REST has become the standard way of creating APIs and exposing resources on the internet. Traditional web services (using SOAP and various sets of WS-* standards) are still used a lot within enterprises, but have pretty much disappeared completely from the public API area and are replaced (or deprecated in favor of) REST based APIs.

REST based APIs are generally easier to use and get started with the SOAP based services and usually don’t require all kinds of code generation to create the messages and the envelopes. However, one thing that is often missing or overlooked, when creating REST based APIs or services is the documentation part. REST doesn’t have a WSDL that is used to describe to service (see section on WADL further down in the article) and often it is said REST resources should be self-documenting. Even though this is easy to say, it’s generally a good idea to provide additional documentation. In this article I’ll show you what you should document and how you can provide this documentation together with your resource.

Lets first look at an example resource. This resource, shown next, represent a report you can make to your local munipality. For instance you notice that a traffic light isn’t functioning, or there is a hole in the road. Your very modern municipality offers a REST based API you can use to report such events.


Content-Type: application/vnd.opengov.org.report+json;charset=UTF-8

{"report": {
     "self": "report-1",                          
     "status": "New",
     "location": "Corner of ninth street",
     "x-coordinate": 52.34,
     "y-coordinate":  4.34,
     "description": "There is ugly graffiti 
                     sprayed on the mailbox at the corner
                     on ninth street",
     "date": "25-11-2010",
     "time": "15:46"
     "images": [
      {"href": "images/image1.png"},               
      {"href": "images/image1.png"}                
     ],
     "related":[
       {"href": "../report-4"},                    
       {"href": "../report-7"},                    
       {"href": "../report-9"}                     
     ]
     "links": [
        {"relation": "invalidation",                                
         "href": "http://localhost:9002/opengov/invalidations/"},  
        {"relation": "duplication",                                 
         "href": "http://localhost:9002/opengov/duplications/"}    
        {"relation": "relation",                                    
         "href": "http://localhost:9002/opengov/relations/"}        
     ]
     "comments": []                                             

    }
}

REST services are often said to be self-documenting. If you look at this resource you can quickly pretty much already understand what this resource represents. It contains some general information about the resource:


     "self": "report-1",                          
     "status": "New",
     "location": "Corner of ninth street",
     "x-coordinate": 52.34,
     "y-coordinate":  4.34,
     "description": "There is ugly graffiti 
                     sprayed on the mailbox at the corner
                     on ninth street",
     "date": "25-11-2010",
     "time": "15:46"

Shows where you can find some related resources such as images related to this report:


    "images": [
      {"href": "images/image1.png"},               
      {"href": "images/image1.png"}                
     ]

Or other reports related to this report:


     "related":[
       {"href": "../report-4"},                    
       {"href": "../report-7"},                    
       {"href": "../report-9"}                     
     ]

Finally from this resource you can also see how you can traverse the links in this resource to report a duplication, invalidate this report or add a related report:


     "links": [
        {"relation": "invalidation",                                
         "href": "http://localhost:9002/opengov/invalidations/"},  
        {"relation": "duplication",                                 
         "href": "http://localhost:9002/opengov/duplications/"}    
        {"relation": "relation",                                    
         "href": "http://localhost:9002/opengov/relations/"}        
     ]

As you can see this REST resource explains itself pretty well. For instance if we want to add a comment to this report we could just use a PUT with a comment message to the /reports/report-1/comments/ URL . But what does this comment message look like? How can we use the links? For this we do need some additional documentation to make our intent clear to the users of our service.

What you should describe are the following items:

  1. URLs used to access or search for a report;
  2. Links relations that describe how various resources are linked together.
  3. Media Types that are used by this service;

Let’s make such a description for this service. The first thing we describe is the URL on which this service can be accessed:


URLs:
http://localhost:9002/opengov/reports?location=xPos,yPos&radius=r
Submit a GET request to this URL to search for Reports. You can optionally specify a location and a radius to only return reports for a specific area. If no location and radius are specified the first 100 reports, sorted by date (newest first), are returned. The reports that are returned have the application/vnd.opengov.org.report+json  media type.
xPos: x-coordinate of the location. Accepts GPS coordinates.
yPos: y-coordinate of the location. Accepts GPS coordinates.
r: radius to search for in meters.

This piece of documentation describes how to use our search service. We also explicitly define the media-type that this service returns. This way consumers already know how to act with the results from this search service. Another important aspect of the documentation are the links we’ve defined:


Links:
self: identifies the current resource. This (relative) URL can be used to directly access or modify a report.

http://localhost:9002/opengov/invalidations/: This URL can be used to invalidate this resource. Use an HTTP PUT operation on this URL with media type application/vnd.opengov.org.invalidation+json. 

http://localhost:9002/opengov/duplications/: This URL can be used to mark a report as a duplicate. Use an HTTP PUT operation on this URL with media type application/vnd.opengov.org.duplication+json.

http://localhost:9002/opengov/relations/: This URL can be used to relate two reports to each other. Use an HTTP PUT operation on this URL with media type application/vnd.opengov.org.invalidation+json.

Here we describe what a specific link implies, how to use it, and what kind of media-types this link expects. That leaves us with describing the resources themselves. If you’re doing REST with XML, you should describe the message using an XSD. If you’re doing JSON you could use JSON-Schema, but I prefer to just describe the fields per media-type.


Media types:
application/vnd.opengov.org.report+json
- status: The status of this report
- location: Readable description of the location of this report
- etc.

If there are any restrictions on these values, this is a good place to describe them. Remember, we write this documentation for human consumption, we don’t require it to be parsable. With the items described above, you’ve got a very good starting point for creating documentation for REST services.

What you should keep in mind are the following items:

  • Follow the basic REST principles for the HTTP PUT, GET, DELETE and POST operations.
  • Use href/links when linking to other resources. It doesn’t really matter if you use relative links or absolute links for this, although relative links are more flexible should you relocate your resource.
  • Use media types to inform your consumer the type of resource they are dealing with.
  • Use links with a specific relation property to tell your consumers what you can do with this resource.
  • Add a simple description of the URLs, media types and links that are supported by your service.

Since I expect someone coming with this question, I’ll answer it beforehand. Why not use a WADL to describe your REST API?

A couple of reasons:

  1. A WADL focusses more on machine-to-machine communication. REST services are more often created to be explored through human interaction. Not by generating a client stub
  2. WADL is a good concept but leans to much towards WSDLs. WSDLs are often used to create RPC based services that hide the underlying protocol. REST APIs are used in a different manner where this approach doesn't fit that well.
  3. An old article, but explains the why/why not of a WADL pretty well: http://bitworking.org/news/193/Do-we-need-WADL

In a follow up article I’ll show you how you can easily provide this documentation to your customers by storing it in a WSO2 Registry and serve it through a http://hostname/service?documentation link.

Updated: