Before we talk about the API that we are going to use, we'll very briefly review the main ideas behind the RESTful approach. Entire books are dedicated to this architectural style, but we will try to convey the essence of what it is in a few paragraphs. So, please, bear with us!
REpresentational State Transfer (REST) is an architectural style for designing web services, which is heavily centered on the notion of resources that is core to the World Wide Web (WWW). The REST architectural style was defined by Roy Fielding in his Ph.D. dissertation (https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm). Interestingly, Mr. Fielding is also one of the main authors of the HTTP specifications.
The main goals of REST are to create loosely coupled, scalable, and efficient applications with simple, consistent, flexible, and easy-to-use interfaces.
To realize these goals, REST defines a set of principles and constraints:
- Client-server: Clients and servers are isolated.
- Stateless: The web service doesn't keep track of its client and each request contains all the information needed.
- Cacheable: Devices between the client and server can cache responses and there is a mechanism to control caching.
- Layered infrastructure: Devices can be placed between the client and server to improve scalability, provide load balancing, and so on.
- Clients and servers communicate through a uniform interface:
- Individual resources are identified in requests (for example, using URIs with HTTP).
- Every element in the API has an identifier (for example, each specific resource instance).
- Resources are separated from the representations that are returned to the client: for example, the server may send data from its data store as JSON or XML, none of which is necessarily the internal representation on the server-side.
- Resources are manipulated through their representation: clients get a representation of specific resources, manipulate those, and then send them back (either partially or fully) to the server so that their changes can be persisted. Those interactions are done via HTTP calls using specific HTTP methods such as PUT or POST and are sent to specific URLs.
- Hypermedia as the Engine of Application State (HATEOAS).
- Resource representations come along with hyperlinks, making it easy for clients to identify possible actions.
- Clients should not assume that any particular action is available for any particular resource.
These are the main constraints that a REST API must adhere to. An API that does not respect all of these constraints is not a truly RESTful API, but rather a web API or REST-like API.
An important point to keep in mind, though, is that REST is NOT a standard. As a matter of fact, there are probably as many different variants of REST APIs as there are APIs. We won't enter into this debate here though; for the rest of this book, we'll talk about REST, RESTful, and web APIs interchangeably (apologies to the purists).
Resources are concrete, high-level concepts (for example, cars, employees, bills) using nouns and lower/kebab case (for example, /api/v1/current-deals). Each resource is associated with a specific URL (for example, /api/v1/cars). If you know how to access one resource type, then accessing another should be easy if the uniformity constraint is respected (for example, /api/v1/employees).
The plural form is used because, usually, resources are collections. For example, we could retrieve the first car in the preceding example at the following URL: /v1/cars/1.
Depending on the considered APIs and domain models, resources can have links to other resources and can have subresources, actions, and so on. For example, assuming that cars have passengers, we could retrieve those passengers via a call to /api/v1/cars/1/passengers. Again, in this case, passengers would be a collection.
URIs have the following structure: URI = scheme "://" authority "/" path [ "? query ] [ "#" fragment ]
Here's an example: https://www.foo.bar/hello-world?param1=value1¶m2=value2#section1
Here are the most important parts of URLs:
- Protocol/scheme: https://
- Subdomain: www
- Domain: foo.bar
- Path: /hello-world
- Query string: ?param1=value1
- Query parameters (key-value pairs):
- param1: value1
- param2: value2
- Separator: &
- Fragment: section1
In addition, here are some points to be aware of regarding resource URLs:
- The query string is used to pass options (for example, paging, filtering, sorting, fields to retrieve or exclude, and many more).
- The body is used for actual contents (for example, complex search criteria).
To manipulate resources, RESTful APIs make use of the different HTTP methods/verbs:
- GET: Retrieves resource representations. This operation is safe, idempotent, and cacheable.
- HEAD: Retrieves headers (no body in the response). This operation is safe, idempotent, and cacheable.
- POST: Creates or partially updates resources. This operation is not safe, nor idempotent.
- PATCH: Update existing resources by patching them. This operation is not safe, nor idempotent.
- DELETE: Deletes resources. This operation is not safe, but idempotent.
- OPTIONS: Gets the allowed options for the target resource. This operation is safe and idempotent.
- PUT: Fully updates a resource. This operation is not safe, but idempotent.
Usually, RESTful APIs expose data as JSON, less often so as XML, and sometimes even both (for example, using parameters to select the format).
HTTP status codes are used to indicate the result of the different operations. There are only a few categories:
- 2xx codes: Success; everything worked.
- 3xx codes: Redirection; no problem occurred, but further actions are required by the client.
- 4xx codes: Client error; the client did something wrong.
- 5xx codes: Server error; the server had a problem.
There are many HTTP status codes, so we can't go through them all. Still, here are a few important ones to know about:
- 200 (OK): Returned when a retrieval/update operation succeeds.
- 201 (Created): Returned after a successful POST creation request.
- 202 (Accepted): Returned when a request has been accepted for processing, but the processing has not completed yet.
- 204 (No content): Returned after a deletion, to indicate that it has succeeded, but that no content is being returned.
- 301 (Moved permanently): Returned when a resource has moved permanently and should be accessed through a different URI.
- 400 (Bad request): The server rejected the request (not understood, not compliant). The request must be modified by the client.
- 401 (Unauthorized): The server rejected the request because the user is not authenticated.
- 403 (Forbidden): The server rejected the request because the user is not authorized/allowed to perform the operation.
- 404 (Not found): The server did not find the requested resource.
- 500 (Internal server error): The server encountered an internal issue.
Finally, RESTful APIs also rely a lot on standard HTTP headers (for example, Accept, Content-Type, Encoding, Cache-Control, ETag, and many more).
There is really a lot more to know about REST APIs, but we'll stop here as it should be just about enough for our purposes.