Best ways to design RESTful APIs
The concept of REST is to separate the API structure into logical resources.Here are some tips that will help you to design RESTful APIs.
Use HTTP Verbs to Make Your Requests Mean Something
API consumers are capable of sending GET, POST, PUT, and DELETE verbs, which greatly enhance the clarity of a given request.
Generally, the four primary HTTP verbs are used as follows:
GET
Read a specific resource (by an identifier) or a collection of resources.
PUT
Update a specific resource (by an identifier) or a collection of resources. Can also be used to create a specific resource if the resource identifier is known before-hand.
DELETE
Remove/delete a specific resource by an identifier.
POST
Create a new resource. Also a catch-all verb for operations that don't fit into the other categories.
Use nouns but no verbs
Use this structure:
GET /movies get all movies
GET /movies/id get a particular movie
Don't use this:
/getAllMovies
/deleteMovie
Use plural nouns
It makes semantic sense when you request many posts from /posts. And for goodness sake don’t consider /post/all with /post/:id .
// plurals are consistent and make sense
GET /v1/posts/:id/attachments/:id/comments
// don't consider ambiguity
// is it just one comment? is it a form? etc.
GET /v1/post/:id/attachment/:id/comment
Use API Versioning
If you’re going to develop an API for any client service, you’re going to want to prepare yourself for eventual change. This is best realised by providing a “version-namespace” for your RESTful API.
We do this with simply adding the version as a prefix to all URLs.
GET www.myservice.com/api/v1/posts
OR we can drop /api also
GET www.myservice.com/v1/posts
Avoid Unnecessary Query Strings
Query strings should be used for further filtering results beyond the initial grouping of a logical set offered by a relationship.
Seek to design endpoint paths that avoid unnecessary query string parameters as they are generally harder to read and to work with, when compared to paths whose structure promotes an initial logical filtering and grouping of such items the deeper it goes.
This /projects/:id/collections is better than /collections?projectId=:id . And this /projects/:id/collections/:id/items is even better than /items?projectId=:id&collectionId=:id .
Use HTTP Status Codes and Error Responses
Because we are using HTTP methods, we should use HTTP status codes. Although a challenge here is to select a distinct slice of these codes, and then depend on response data to detail any response errors. Keeping a small set of codes helps you consume and handle errors consistently.
I like to use:
for Data Errors
- 400 for when the requested information is incomplete or malformed.
- 422 for when the requested information is okay, but invalid.
- 404 for when everything is okay, but the resource doesn’t exist.
- 409 for when a conflict of data exists, even with valid information.
for Auth Errors
- 401 for when an access token isn’t provided, or is invalid.
- 403 for when an access token is valid, but requires more privileges.
for Standard Statuses
- 200 for when everything is okay.
- 204 for when everything is okay, but there’s no content to return.
- 500 for when the server throws an error, completely unexpected.
Consider Connectedness
One of the principles of REST is connectedness—via hypermedia links (search HATEOAS). While services are still useful without them, APIs become more self-descriptive and discoverable when links are returned in the response. At the very least, a 'self' link reference informs clients how the data was or can be retrieved. Additionally, utilize the HTTP Location header to contain a link on resource creation via POST (or PUT). For collections returned in a response that support pagination, 'first', 'last', 'next' and 'prev' links at a minimum are very helpful.
Regarding linking formats, there are many. The HTTP Web Linking Specification explains a link as follows:
a link is a typed connection between two resources that are identified by Internationalised Resource Identifiers (IRIs), and is comprised of:
- A context IRI,
- a link relation type
- a target IRI, and
- optionally, target attributes.
A link can be viewed as a statement of the form "{context IRI} has a {relation type} resource at {target IRI}, which has {target attributes}."
Cross-Origin Resource Sharing (CORS)
It is important to consider that when placing your API into a different subdomain such as api.myservice.com it will require implementing CORS for your backend if you plan to host your frontend site at www.myservice.com and expect to use AJAX calls without throwing No Access-Control-Allow-Origin header is present errors.
Use Access and Refresh Tokens
Modern stateless, RESTful APIs implement authentication with tokens. This eliminates the need to handle sessions and cookies on a now stateless server, and makes it really easy to debug network requests by simply utilising the Authorization header (or even an access_token query param).
Engineering @ AWS
7yHEAD and OPTIONS are also two useful verbs that could be used as "nice to have" features in your RESTful application. For example, if you wanted to advertise all the possible URIs available in your application you could have a base controller (/v1/<base>) respond to an OPTIONS request with a payload containing all the links. HEAD request can be used to see whether content has changed since the last GET request, and the upside is since the message body is not returned, the network bandwidth is not consumed. Also, HEAD could be used to provide other useful information such as the server setup, whether the server is up or down (health check) etc.