We may work in a development environment where we are designing applications which need to access information through web services.
As part of the development process, we may be asked to design the interfaces – or APIs – to new web services.
This article gives an approach to designing logical APIs using the REST approach which is suitable for designers who don't need to understand how the API will be technically implemented.
Background
People have been wanting to create web services that worked across the internet using HTTP.
The problem is that there was no standard for how to do this – early development saw no consistency in the use of HTTP operations (GET, POST, etc.), responses, and structure of URLs.
The REST API approach is an attempt to apply a standard for web services over HTTP.
Thinking about resources
The first step in designing a REST API, is to think about the 'resources' that the web service will need access to.
This step is essentially an exercise in data analysis, in which we work out the entities - termed 'resources' or 'endpoints' in the REST API approach - which the web service will need to access.
Let's use the example of a bank or building society which needs to design some APIs to provide public access to its information. It may be that it needs to provide:
- A directory of all its branches
- The locations of all its ATMs
- A list of the products that it provides
When determining the resources that we need to give access to, name each resource as a plural noun.
Using this approach, we might come up with the following resources:
- branches
- ATMs
- products
The way that HTTP gets access to a resource is using a 'uniform resource locator', or URL. You will be familiar with a URL, as that's what you use to access a website.
When your API is implemented, you can think of it as having a base URL - say:
apis.finstitute.co.uk
Then each of the resources can be implemented as a continuation of this URL:
apis.finstitute.co.uk/branches
apis.finstitute.co.uk/ATMs
apis.finstitute.co.uk/products
Web service operations
The web service we're designing may have many functions or operations, but using the REST approach, we can think of the user of our web service wanting to operate on a resource, or number of resources.
If we imagine a resource to be a database, then the operations that we want our web service to perform can be summarised as:
- Adding an item to a database
- Reading items from a database
- Updating an item on a database, and
- Deleting an item from a database
This analysis of operations, also known as Create, Read, Update, Delete, or CRUD, can be mapped to existing HTTP methods:
- Create maps to
POST
- Read maps to
GET
- Update maps to
PUT
- Delete maps to
DELETE
Putting the operation and resource together
Putting together the operation and resource, you can create a catalogue of APIs, for example:
GET apis.finstitute.co.uk/ATMs
might get you a list of all the institution's ATMs.
Assuming each resource has a unique identifier, then this can be added to the URL to specify an individual resource. So, for example:
GET apis.finstitute.co.uk/ATMs/AB461881
could get you the details of the ATM with the unique identifier "AB461881".
Sub-resources
It could be that the information that you get back from a resource lends itself to specifying a 'sub-resource'. For example, each ATM may have a list of services available on that ATM. This could be specified using a sub-resource as follows:
GET apis.finstitute.co.uk/ATMs/AB461881/ATMservices
In this example, the user is asking for the list of ATM services for the ATM with the unique identifier "AB461881".
Filtering
Rather than getting the whole list, a query string can be used to imply a filter, for example:
GET apis.finstitute.co.uk/ATMs?postcode="SA36"
could be used to show all ATMs which are in the SA36 postcode area.
Ordering
A query string could also specify an order, for example:
GET apis.finstitute.co.uk/ATMs?order=postcode
could be used to show all ATMs in postcode order.
Transfer of data
So far, we've talked about how to determine the resources that your users need access to, and the operations that they'll need to perform.
The next element of API design concerns the transfer of data across the API boundary.
This data is known as the 'payload', and it's used for:
- Specifying the response that the user when they issue a
GET
- Sending data when creating a new record, as part of a
POST
- Or sending data when updating a record, as part of a
PUT
The preferred method of specifying the data in the payload is using JSON. This has won the battle over XML, as JSON is generally more consumable by the JavaScript applications using REST APIs.
JSON is a way of specifying a series of key and value pairs in a structured way.
Let's look at the example again, where we got the details for a specific ATM.
GET apis.finstitute.co.uk/ATMs/AB461881
The sort of response that we get back might include:
- The unique identifier of the ATM
- Languages supported by the ATM
- ATM services offered
- Location of the ATM
In JSON, this might look like:
[
{
"ID": "AB461881",
"supportedLanguages": [
"en",
"cy"
],
"ATMservices": [
"CashWithdrawal",
"PINChange",
"MobilePhoneTopUp",
"Balance",
"MiniStatement",
"CharityDonation"
],
"postcode": "SA36 0ED"
}
]
Putting together the operations and payload to do transactions
The same data as we get in the GET
response could be used to create a record for a new ATM. If we imagine an administrator, who has permission to add new ATMs, they might issue a call to the web service as follows:
POST apis.finstitute.co.uk/ATMs/CZ312516
and in this case, the user would send a payload with the call containing the details of the new ATM:
[
{
"ID": "CZ312516",
"supportedLanguages": [
"en"
],
"ATMservices": [
"CashWithdrawal",
"PINChange",
"MobilePhoneTopUp",
"Balance",
"CharityDonation"
],
"postcode": "SN12 9DN"
}
]
Let's say the administrator made a mistake with the postcode, and needs to update it. Then they could issue a PUT
request:
PUT apis.finstitute.co.uk/ATMs/CZ312516
this time just sending the data that needs to be updated:
[
{
"postcode": "SN12 9DM"
}
]
Status responses
The REST API approach also standardises the way that the web service responds to say whether the call has been successful, or there was an error.
HTTP has a standard set of status codes, and subset of these can be used in your API design. For example:
200
- OK. Can be used for a successful response404
- Not found. Say you specify a unique identifier, and it doesn't exist500
- Error. Some sort of technical error has occurred. This could be accompanied by an error message, or messages, in the payload.
Conclusion
So in this article, we've looked at:
- How to think about the resources you access to, and how to specify these in a URL
- Designing the operations on the web service, using standard HTTP methods
- Structuring the data in the payload using JSON
- Using standard HTTP status codes for successful and failure responses
Links
Here are some useful links and references which I found when putting this article together.
How to Connect to an API with JavaScript - A practical example of how to use a set of APIs published by Studio Ghibli, by web developer Tania Rascia. Her site is a great resource in general for demystifying some of the concepts in web development
ATM API Specification - v2.2.0 - The actual Open Banking API spec for ATMs, in case you're interested
JSON.org - The reference site for JSON