Hypermedia is a term that originated with the beginnings of the World Wide Web to explain how browsers could adapt their features to any type of media (text, XML, JSON, images, video, etc.) using MIME types.  The term has been expanded to be applied primarily to REST based APIs to describe a model for API creation where the relationship between resources and the available actions the user can take are represented with links returned with each request.

For example, this PayPal REST API (GET /v1/payments/sale/<Transaction-Id>) returns the following JSON with a links array of available actions including self, refund, and parent_payment.


{
  "id": "36C38912MN9658832",
  "create_time": "2013-02-19T22:01:53Z",
  "update_time": "2013-02-19T22:01:55Z",
  "state": "completed",
  "amount": {
    "currency": "USD",
    "total": "7.47"
  },
  "protection_eligibility": "ELIGIBLE",
  "protection_eligibility_type": "UNAUTHORIZED_PAYMENT_ELIGIBLE",
  "transaction_fee": {
    "value": "1.75",
    "currency": "USD"
  },
  "parent_payment": "PAY-5YK922393D847794YKER7MUI",
  "links": [
    {
      "href": "https://api.sandbox.paypal.com/v1/payments/sale/36C38912MN9658832",
      "rel": "self",
      "method": "GET"
    },
    {
      "href": "https://api.sandbox.paypal.com/v1/payments/sale/36C38912MN9658832/refund",
      "rel": "refund",
      "method": "POST"
    },
    {
      "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAY-5YK922393D847794YKER7MUI",
      "rel": "parent_payment",
      "method": "GET"
    }
  ]
}

There are four favored hypermedia protocols in use, although many others have been proposed.

Collection+JSON

This is a protocol that uses JavaScript Object Notation and specifies the use of links, list of items, queries, and template.


{ &quot;collection&quot; :
  {
    &quot;version&quot; : &quot;1.0&quot;,
    &quot;href&quot; : &quot;http://example.org/friends/&quot;,

<pre><code>&amp;quot;links&amp;quot; : [
  {&amp;quot;rel&amp;quot; : &amp;quot;feed&amp;quot;, &amp;quot;href&amp;quot; : &amp;quot;http://example.org/friends/rss&amp;quot;}
],

&amp;quot;items&amp;quot; : [
  {
    &amp;quot;href&amp;quot; : &amp;quot;http://example.org/friends/jdoe&amp;quot;,
    &amp;quot;data&amp;quot; : [
      {&amp;quot;name&amp;quot; : &amp;quot;full-name&amp;quot;, &amp;quot;value&amp;quot; : &amp;quot;J. Doe&amp;quot;, &amp;quot;prompt&amp;quot; : &amp;quot;Full Name&amp;quot;},
      {&amp;quot;name&amp;quot; : &amp;quot;email&amp;quot;, &amp;quot;value&amp;quot; : &amp;quot;[email protected]&amp;quot;, &amp;quot;prompt&amp;quot; : &amp;quot;Email&amp;quot;}
    ],
    &amp;quot;links&amp;quot; : [
      {&amp;quot;rel&amp;quot; : &amp;quot;blog&amp;quot;, &amp;quot;href&amp;quot; : &amp;quot;http://examples.org/blogs/jdoe&amp;quot;, &amp;quot;prompt&amp;quot; : &amp;quot;Blog&amp;quot;},
      {&amp;quot;rel&amp;quot; : &amp;quot;avatar&amp;quot;, &amp;quot;href&amp;quot; : &amp;quot;http://examples.org/images/jdoe&amp;quot;, &amp;quot;prompt&amp;quot; : &amp;quot;Avatar&amp;quot;, &amp;quot;render&amp;quot; : &amp;quot;image&amp;quot;}
    ]
  },

  {
    &amp;quot;href&amp;quot; : &amp;quot;http://example.org/friends/msmith&amp;quot;,
    &amp;quot;data&amp;quot; : [
      {&amp;quot;name&amp;quot; : &amp;quot;full-name&amp;quot;, &amp;quot;value&amp;quot; : &amp;quot;M. Smith&amp;quot;, &amp;quot;prompt&amp;quot; : &amp;quot;Full Name&amp;quot;},
      {&amp;quot;name&amp;quot; : &amp;quot;email&amp;quot;, &amp;quot;value&amp;quot; : &amp;quot;[email protected]&amp;quot;, &amp;quot;prompt&amp;quot; : &amp;quot;Email&amp;quot;}
    ],
    &amp;quot;links&amp;quot; : [
      {&amp;quot;rel&amp;quot; : &amp;quot;blog&amp;quot;, &amp;quot;href&amp;quot; : &amp;quot;http://examples.org/blogs/msmith&amp;quot;, &amp;quot;prompt&amp;quot; : &amp;quot;Blog&amp;quot;},
      {&amp;quot;rel&amp;quot; : &amp;quot;avatar&amp;quot;, &amp;quot;href&amp;quot; : &amp;quot;http://examples.org/images/msmith&amp;quot;, &amp;quot;prompt&amp;quot; : &amp;quot;Avatar&amp;quot;, &amp;quot;render&amp;quot; : &amp;quot;image&amp;quot;}
    ]
  },

  {
    &amp;quot;href&amp;quot; : &amp;quot;http://example.org/friends/rwilliams&amp;quot;,
    &amp;quot;data&amp;quot; : [
      {&amp;quot;name&amp;quot; : &amp;quot;full-name&amp;quot;, &amp;quot;value&amp;quot; : &amp;quot;R. Williams&amp;quot;, &amp;quot;prompt&amp;quot; : &amp;quot;Full Name&amp;quot;},
      {&amp;quot;name&amp;quot; : &amp;quot;email&amp;quot;, &amp;quot;value&amp;quot; : &amp;quot;[email protected]&amp;quot;, &amp;quot;prompt&amp;quot; : &amp;quot;Email&amp;quot;}
    ],
    &amp;quot;links&amp;quot; : [
      {&amp;quot;rel&amp;quot; : &amp;quot;blog&amp;quot;, &amp;quot;href&amp;quot; : &amp;quot;http://examples.org/blogs/rwilliams&amp;quot;, &amp;quot;prompt&amp;quot; : &amp;quot;Blog&amp;quot;},
      {&amp;quot;rel&amp;quot; : &amp;quot;avatar&amp;quot;, &amp;quot;href&amp;quot; : &amp;quot;http://examples.org/images/rwilliams&amp;quot;, &amp;quot;prompt&amp;quot; : &amp;quot;Avatar&amp;quot;, &amp;quot;render&amp;quot; : &amp;quot;image&amp;quot;}
    ]
  }      
],

&amp;quot;queries&amp;quot; : [
  {&amp;quot;rel&amp;quot; : &amp;quot;search&amp;quot;, &amp;quot;href&amp;quot; : &amp;quot;http://example.org/friends/search&amp;quot;, &amp;quot;prompt&amp;quot; : &amp;quot;Search&amp;quot;,
    &amp;quot;data&amp;quot; : [
      {&amp;quot;name&amp;quot; : &amp;quot;search&amp;quot;, &amp;quot;value&amp;quot; : &amp;quot;&amp;quot;}
    ]
  }
],

&amp;quot;template&amp;quot; : {
  &amp;quot;data&amp;quot; : [
    {&amp;quot;name&amp;quot; : &amp;quot;full-name&amp;quot;, &amp;quot;value&amp;quot; : &amp;quot;&amp;quot;, &amp;quot;prompt&amp;quot; : &amp;quot;Full Name&amp;quot;},
    {&amp;quot;name&amp;quot; : &amp;quot;email&amp;quot;, &amp;quot;value&amp;quot; : &amp;quot;&amp;quot;, &amp;quot;prompt&amp;quot; : &amp;quot;Email&amp;quot;},
    {&amp;quot;name&amp;quot; : &amp;quot;blog&amp;quot;, &amp;quot;value&amp;quot; : &amp;quot;&amp;quot;, &amp;quot;prompt&amp;quot; : &amp;quot;Blog&amp;quot;},
    {&amp;quot;name&amp;quot; : &amp;quot;avatar&amp;quot;, &amp;quot;value&amp;quot; : &amp;quot;&amp;quot;, &amp;quot;prompt&amp;quot; : &amp;quot;Avatar&amp;quot;}

  ]
}
</code></pre>

} 
}

HAL

Hypertext Application Language is a relatively simple model that specifies the use of resources and links only.  The links section can also include a “curies” reference to online documentation of the API.


{
    "_links": {
        "self": { "href": "/orders" },
        "curies": [{ "name": "ea", "href": "http://example.com/docs/rels/{rel}", "templated": true }],
        "next": { "href": "/orders?page=2" },
        "ea:find": {
            "href": "/orders{?id}",
            "templated": true
        },
        "ea:admin": [{
            "href": "/admins/2",
            "title": "Fred"
        }, {
            "href": "/admins/5",
            "title": "Kate"
        }]
    },
    "currentlyProcessing": 14,
    "shippedToday": 20,
    "_embedded": {
        "ea:order": [{
            "_links": {
                "self": { "href": "/orders/123" },
                "ea:basket": { "href": "/baskets/98712" },
                "ea:customer": { "href": "/customers/7809" }
            },
            "total": 30.00,
            "currency": "USD",
            "status": "shipped"
        }, {
            "_links": {
                "self": { "href": "/orders/124" },
                "ea:basket": { "href": "/baskets/97213" },
                "ea:customer": { "href": "/customers/12369" }
            },
            "total": 20.00,
            "currency": "USD",
            "status": "processing"
        }]
    }
}

Siren
Siren is a hypermedia specification for representing Resources as Entites with links for navigation and actions for expressing user actions that can be performed along with UI prompting.
{
  "class": [ "order" ],
  "properties": { 
      "orderNumber": 42, 
      "itemCount": 3,
      "status": "pending"
  },
  "entities": [
    { 
      "class": [ "items", "collection" ], 
      "rel": [ "http://x.io/rels/order-items" ], 
      "href": "http://api.x.io/orders/42/items"
    },
    {
      "class": [ "info", "customer" ],
      "rel": [ "http://x.io/rels/customer" ], 
      "properties": { 
        "customerId": "pj123",
        "name": "Peter Joseph"
      },
      "links": [
        { "rel": [ "self" ], "href": "http://api.x.io/customers/pj123" }
      ]
    }
  ],
  "actions": [
    {
      "name": "add-item",
      "title": "Add Item",
      "method": "POST",
      "href": "http://api.x.io/orders/42/items",
      "type": "application/x-www-form-urlencoded",
      "fields": [
        { "name": "orderNumber", "type": "hidden", "value": "42" },
        { "name": "productCode", "type": "text" },
        { "name": "quantity", "type": "number" }
      ]
    }
  ],
  "links": [
    { "rel": [ "self" ], "href": "http://api.x.io/orders/42" },
    { "rel": [ "previous" ], "href": "http://api.x.io/orders/41" },
    { "rel": [ "next" ], "href": "http://api.x.io/orders/43" }
  ]
}

XHTML

XHTML is synonymous with well-formed HTML.  It’s use in an API is similar to that of an HTML page with the available tags and elements, but leaves the interpretation largely to the client.

API Documentation

Nearly every API requires some amount of documentation.  The documentation most commonly takes the form of a metadata JSON file.  There are three primary API documentation formats in use.

APIBlueprint

This format uses a Markdown style documentation format that generates more verbose JSON metadata.

APIBlueprint


# GET /message
+ Response 200 (text/plain)
Hello World!

JSON Output


{
    "_version": "3.0",
    "metadata": [],
    "name": "",
    "description": "",
    "element": "category",
    "resourceGroups": [
        {
            "name": "",
            "description": "",
            "resources": [
                {
                    "element": "resource",
                    "name": "",
                    "description": "",
                    "uriTemplate": "/message",
                    "model": {},
                    "parameters": [],
                    "actions": [
                        {
                            "name": "",
                            "description": "",
                            "method": "GET",
                            "parameters": [],
                            "attributes": {
                                "relation": "",
                                "uriTemplate": ""
                            },
                            "content": [],
                            "examples": [
                                {
                                    "name": "",
                                    "description": "",
                                    "requests": [],
                                    "responses": [
                                        {
                                            "name": "200",
                                            "description": "",
                                            "headers": [
                                                {
                                                    "name": "Content-Type",
                                                    "value": "text/plain"
                                                }
                                            ],
                                            "body": "Hello World!n",
                                            "schema": "",
                                            "content": [
                                                {
                                                    "element": "asset",
                                                    "attributes": {
                                                        "role": "bodyExample"
                                                    },
                                                    "content": "Hello World!n"
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ]
                        }
                    ],
                    "content": []
                }
            ]
        }
    ],
    "content": [
        {
            "element": "category",
            "content": [
                {
                    "element": "resource",
                    "name": "",
                    "description": "",
                    "uriTemplate": "/message",
                    "model": {},
                    "parameters": [],
                    "actions": [
                        {
                            "name": "",
                            "description": "",
                            "method": "GET",
                            "parameters": [],
                            "attributes": {
                                "relation": "",
                                "uriTemplate": ""
                            },
                            "content": [],
                            "examples": [
                                {
                                    "name": "",
                                    "description": "",
                                    "requests": [],
                                    "responses": [
                                        {
                                            "name": "200",
                                            "description": "",
                                            "headers": [
                                                {
                                                    "name": "Content-Type",
                                                    "value": "text/plain"
                                                }
                                            ],
                                            "body": "Hello World!n",
                                            "schema": "",
                                            "content": [
                                                {
                                                    "element": "asset",
                                                    "attributes": {
                                                        "role": "bodyExample"
                                                    },
                                                    "content": "Hello World!n"
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ]
                        }
                    ],
                    "content": []
                }
            ]
        }
    ]
}

RAML

RAML is a slightly more verbose method of defining an API with a number of parsers available including JavaScript and .NET.


#%RAML 0.8
 
title: World Music API
baseUri: http://example.api.com/{version}
version: v1
traits:
  - paged:
      queryParameters:
        pages:
          description: The number of pages to return
          type: number
  - secured: !include http://remote-host/secured.yml
/songs:
  is: [ paged, secured ]
  get:
    queryParameters:
      genre:
        description: filter the songs by genre
  post:
  /{songId}:
    get:
      responses:
        200:
          body:
            application/json:
              schema: |
                { "$schema": "http://json-schema.org/schema",
                  "type": "object",
                  "description": "A canonical song",
                  "properties": {
                    "title":  { "type": "string" },
                    "artist": { "type": "string" }
                  },
                  "required": [ "title", "artist" ]
                }
            application/xml:
    delete:
      description: |
        This method will *delete* an **individual song**

Swagger

Swagger is another popular documentation format with support for API generation directly in WebAPI projects via the Swashbuckle NuGet package.  It also includes the ability to document the Authentication model used to call the API.

Note:  Swagger is being adopted by Microsoft for it’s Azure Logic App connections and other APIs.


# this is an example of the Uber API
# as a demonstration of an API spec in YAML
swagger: '2.0'
info:
  title: Uber API
  description: Move your app forward with the Uber API
  version: "1.0.0"
# the domain of the service
host: api.uber.com
# array of all schemes that your API supports
schemes:
  - https
# will be prefixed to all paths
basePath: /v1
produces:
  - application/json
paths:
  /products:
    get:
      summary: Product Types
      description: |
        The Products endpoint returns information about the *Uber* products
        offered at a given location. The response includes the display name
        and other details about each product, and lists the products in the
        proper display order.
      parameters:
        - name: latitude
          in: query
          description: Latitude component of location.
          required: true
          type: number
          format: double
        - name: longitude
          in: query
          description: Longitude component of location.
          required: true
          type: number
          format: double
      tags:
        - Products
      responses:
        200:
          description: An array of products
          schema:
            type: array
            items:
              $ref: '#/definitions/Product'
        default:
          description: Unexpected error
          schema:
            $ref: '#/definitions/Error'
  /estimates/price:
    get:
      summary: Price Estimates
      description: |
        The Price Estimates endpoint returns an estimated price range
        for each product offered at a given location. The price estimate is
        provided as a formatted string with the full price range and the localized
        currency symbol.

The response also includes low and high estimates, and the [ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code for situations requiring currency conversion. When surge is active for a particular product, its surge_multiplier will be greater than 1, but the price estimate already factors in this multiplier. parameters: - name: start_latitude in: query description: Latitude component of start location. required: true type: number format: double - name: start_longitude in: query description: Longitude component of start location. required: true type: number format: double - name: end_latitude in: query description: Latitude component of end location. required: true type: number format: double - name: end_longitude in: query description: Longitude component of end location. required: true type: number format: double tags: - Estimates responses: 200: description: An array of price estimates by product schema: type: array items: $ref: '#/definitions/PriceEstimate' default: description: Unexpected error schema: $ref: '#/definitions/Error' /estimates/time: get: summary: Time Estimates description: The Time Estimates endpoint returns ETAs for all products offered at a given location, with the responses expressed as integers in seconds. We recommend that this endpoint be called every minute to provide the most accurate, up-to-date ETAs. parameters: - name: start_latitude in: query description: Latitude component of start location. required: true type: number format: double - name: start_longitude in: query description: Longitude component of start location. required: true type: number format: double - name: customer_uuid in: query type: string format: uuid description: Unique customer identifier to be used for experience customization. - name: product_id in: query type: string description: Unique identifier representing a specific product for a given latitude & longitude. tags: - Estimates responses: 200: description: An array of products schema: type: array items: $ref: '#/definitions/Product' default: description: Unexpected error schema: $ref: '#/definitions/Error' /me: get: summary: User Profile description: The User Profile endpoint returns information about the Uber user that has authorized with the application. tags: - User responses: 200: description: Profile information for a user schema: $ref: '#/definitions/Profile' default: description: Unexpected error schema: $ref: '#/definitions/Error' /history: get: summary: User Activity description: The User Activity endpoint returns data about a user's lifetime activity with Uber. The response will include pickup locations and times, dropoff locations and times, the distance of past requests, and information about which products were requested.

The history array in the response will have a maximum length based on the limit parameter. The response value count may exceed limit, therefore subsequent API requests may be necessary. parameters: - name: offset in: query type: integer format: int32 description: Offset the list of returned results by this amount. Default is zero. - name: limit in: query type: integer format: int32 description: Number of items to retrieve. Default is 5, maximum is 100. tags: - User responses: 200: description: History information for the given user schema: $ref: '#/definitions/Activities' default: description: Unexpected error schema: $ref: '#/definitions/Error' definitions: Product: properties: product_id: type: string description: Unique identifier representing a specific product for a given latitude & longitude. For example, uberX in San Francisco will have a different product_id than uberX in Los Angeles. description: type: string description: Description of product. display_name: type: string description: Display name of product. capacity: type: string description: Capacity of product. For example, 4 people. image: type: string description: Image URL representing the product. PriceEstimate: properties: product_id: type: string description: Unique identifier representing a specific product for a given latitude & longitude. For example, uberX in San Francisco will have a different product_id than uberX in Los Angeles currency_code: type: string description: "[ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code." display_name: type: string description: Display name of product. estimate: type: string description: Formatted string of estimate in local currency of the start location. Estimate could be a range, a single number (flat rate) or "Metered" for TAXI. low_estimate: type: number description: Lower bound of the estimated price. high_estimate: type: number description: Upper bound of the estimated price. surge_multiplier: type: number description: Expected surge multiplier. Surge is active if surge_multiplier is greater than 1. Price estimate already factors in the surge multiplier. Profile: properties: first_name: type: string description: First name of the Uber user. last_name: type: string description: Last name of the Uber user. email: type: string description: Email address of the Uber user picture: type: string description: Image URL of the Uber user. promo_code: type: string description: Promo code of the Uber user. Activity: properties: uuid: type: string description: Unique identifier for the activity Activities: properties: offset: type: integer format: int32 description: Position in pagination. limit: type: integer format: int32 description: Number of items to retrieve (100 max). count: type: integer format: int32 description: Total number of items available. history: type: array items: $ref: '#/definitions/Activity' Error: properties: code: type: integer format: int32 message: type: string fields: type: string

The following is a table comparing the features of each documentation model and can be found here.