A common design style of Web API is RPC-style (Remote Procedure Call). A RPC-style Web API allocates one URL for each function or operation. These URLs represent an action and are usually named with a verb. The following table shows five endpoints in a Web API to manipulate products in a database. They implement four common operations on data known as CRUD (Create, Retrieve, Update and Delete).
method | URL | function |
---|---|---|
GET | /products.info | Retrieve info about a specific product |
GET | /products.list | List all products |
POST | /products.create | Add a new product |
POST | /products.update | Update a product |
POST | /products.delete | Delete a product |
Each endpoint is identified with the HTTP method (either GET or POST) and an URL. An endpoint uses GET if the operation is read-only. If the operation may cause some action or side-effect on the server side, the endpoint must use POST.
In addition, when you design a Web API, you also need to specify:
Readonly endpoints in RPC-style Web APIs should use the GET method. This informs the proxy servers that the responses from these endpoints are cacheable, and may be reused within an expiry time.
A Web API may return result in either URL-encoded (i.e. key-value pairs) or JSON. Key-value pairs are only suitable for simple values. JSON is more flexible in representing data structure.
Below is a sample HTTP request to retrieve a product with a specified ID:
GET /products.info?id=5 HTTP/1.1
Host: example.com
Below is a sample response message returned by the Web API. The JSON payload has Content-type: application/json
.
HTTP/1.1 200 Ok
Content-type: application/json
Content-length: 116
{
"id": 5,
"productName": "Coke candy",
"category": "Confections",
"unitPrice": 10.5,
"unitsInStock": 20
}
Similarly, search operations should use the GET
verb because they are readonly operations. You can design the parameters to specify the search criteria. For example, to list all ‘confections’ products with a unit price less than or equal to $10, you can implement the parameters category
and maxUnitPrice
for filtering the result set. The client can then send the following request.
GET /products.list?category=Confections&maxUnitPrice=10 HTTP/1.1
Host: example.com
HTTP/1.1 200 Ok
Content-type: application/json
Content-length: 6060
{
"count": 98,
"items": [
{ "id": 5, "productName": "Coke candy", "unitPrice": 10.5 ... },
{ "id": 6, "productName": "Chocolate bar", "unitPrice": 25.0 ...},
...
]
}
The endpoints of any update operations must use POST. It indicates that any web proxy servers between the client and the Web API should not cache responses of the operations. In update operations, there are usually some input parameters. In your design of the API, you can choose either to use simple parameters as URL-encoded (i.e. key-value pairs) or JSON data in the request message body.
Below is a sample request for adding a new product products.create
in the Web API.
POST /products.create HTTP/1.1
Host: example.com
Content-type: application/x-www-form-urlencoded
Content-length: 53
productName=Great+new+chocolate&category=Confections&unitPrice=20&unitsInStock=100
And the equivalent version using JSON payload.
POST /products.create HTTP/1.1
Host: example.com
Content-type: application/json
Content-length: 113
{
"productName": "Great new chocolate",
"category": "Confections",
"unitPrice": 20,
"unitsInStock": 100
}
URL-encoded payload is commonly used in Web APIs in client side of modern web apps. One reason is that the input parameters are usually simple in these APIs. Furthermore, it is easier to work with key-value pairs in client-side programming.
In this chapter, we’ll mostly use JSON payload for simplicity.
A successful response from an update operation may provide some info about the update operation, e.g. the id of the newly created record. Alternatively, the API designer may choose to return a representation of the newly created product as follows.
HTTP/1.1 200 Ok
Content-type: application/json
Content-length: 125
{
"id": 21,
"productName": "Great new chocolate",
"category": "Confections",
"unitPrice": 20,
"unitsInStock": 100
}
In the product.update
endpoint, the client must specify the id
of the product to change, and then list the properties and their new values.
POST /products.update HTTP/1.1
Host: example.com
Content-type: application/json
Content-length: 141
{
"id": 5,
"productName": "Coke candy (Update price and stock)",
"category": "Confections",
"unitPrice": 13.8,
"unitsInStock": 32
}
After successful update of the item, the server usually returns a 200
response with the updated representation of the item in the response body. This is similar to the response for adding a new product.
For the delete operation, the client must specify the id
of product to delete in the products.delete
endpoint.
POST /products.delete HTTP/1.1
Host: example.com
Content-type: application/x-www-form-urlencoded
Content-length: 4
id=3
An equivalent version using JSON payload follows.
POST /products.delete HTTP/1.1
Host: example.com
Content-type: application/json
Content-length: 10
{ "id":3 }
Some API designers prefer to pass simple parameters as URL query in POST requests, for example …
POST /products.delete?id=3 HTTP/1.1 Host: example.com
A successful response for the delete operation usually contains no data. The Web API designer may choose a response with no body using the 204
status code,
HTTP/1.1 204 No content
or, for consistency, a response with an empty JSON value.
HTTP/1.1 200 Ok
Host: example.com
Content-type: application/json
Content-length: 2
{}
The Slack API is a popular Web API that use the RPC style. Consider, for example, the numerous endpoints in the conversations method group. These endpoints allow a client to create a channel, join a channel, leave a channel, kick someone out of a channel, invite someone to join a channel, and list the messages in a channel.