Principles & Best Practices of REST API Design
This best-practices article intends for developers interested in creating RESTful Web services that provided high reliability and consistency across multiple services suites
This best-practices article intends for developers interested in creating RESTful Web services that provided high reliability and consistency across multiple services suites; following these guidelines; services are positioned for rapid, widespread, public adoption by internal and external clients.
Here is the complete diagram to easily understand RES API’s principles, methods and best practices.
Now, let’s begin with elaborating on each box by starting with tis principles.
The Six Principles / Constraints
Client-Server
Separation of concerns is the principle behind the client-server constraints. By separating the user interface concerns from the data storage concerns, we improve the portability of the user interface across multiple platforms and improve scalability by simplifying the server components.
Stateless
Communication must be stateless, as in the client-stateless-server (CSS) style. Each request from the client to server must contain all of the information necessary to understand the request. Session state is therefore kept entirely on the client.
Cacheable
To improve network efficiency, we add cache constrains to form the client-cache-stateless-server style. Cache constraints require that the data respond to a request with the implicit or explicit label as cacheable or non-cacheable. If a response is cacheable, then a client cache is given the right to reuse that response data for later, equivalent request.
Layered System
A client cannot ordinarily tell whether it is connected directly to the end server or an intermediary along the way. Intermediary servers may improve system scalability by enabling load-balancing and by providing shared caches. Layers may also enforce security policies.
Code-on-Demand
REST allows client functionality to extend by downloading and executing code in the form of applets or scripts. Simplifies clients by reducing the number of features required to be pre-implemented. It allows features to download after deployment improves system extensibility.
Uniform Interface
By applying the software engineering principle of generality to the component interface, the overall system architecture becomes simplified, and the visibility of interactions is improved. Implementations decouple from the services they provide, which encourages independent evolvability. REST defines by four interface constraints: identification of resources, manipulation of resources through representations, self-descriptive messages, and Hypermedia as the engine of application state.
Self-descriptive Messages: Each message includes enough information to describe how to process the message.
Resource-Based: Individual resources are identified in request using URLs as resource identifiers. The resources themselves are conceptually separate from the representation that returns to the client.
Manipulation of Resources through Representations: When a client represents a resource, including any metadata attached, it has enough information to modify or delete the resource on the server, provided it has permission to do so.
Hypermedia as the Engine of Application State (HATEOAS): clients deliver state via body contents, query-string parameters, request headers, and the requested URL (the resource name). Services provide the state to clients via body content, response codes, and response headers.
Best Practices
Now, let’s change the gear to understand REST’s essential best practice, which every engineer should know.
Keep it Simple and Fine-Grained
Create API’s that mimic your system’s underlying application domain or database architecture of your system. Eventually, you’ll want aggregate services — services that utilize multiple underlying resources to reduce chattiness.
Filtering & Ordering
For large data sets, limiting the amount of data returned is vital from a bandwidth standpoint. Additionally, we may want to specify the fields or properties of a resource to be included in the response, thereby limiting the amount of data that comes back. We eventually want to query for specific values and sort the returned data.
Versioning
There are many ways to break a contract and negatively impact your clients in API development. If you are uncertain of the consequences of your changes, it is better to play it safe and consider versioning. There are several factors to consider when deciding if a new version is appropriate or if a modification of the existing representation is sufficient and acceptable. Since maintaining many versions becomes cumbersome, complex, error-prone, and costly, you should support no more than two versions for any given resource.
Cache
Caching enhances scalability by enabling layers in the system to eliminate remote calls to retrieve requested data. Services improve cache-ability by setting headers on responses such as Cache-Control, Expires, Pragma, Last-Modified etc.
Pagination
One of the principles of REST is connectedness via hypermedia links. At the same time, services are still helpful without them. APIs become more self-descriptive when links return in the response. For collections returned in a response that supports Pagination, ‘first’, ‘last’, ‘next’, and ‘prev’ links at a minimum are beneficial.
Resource-Naming
An API is intuitive and easy to use when resources are named well. Done poorly, that same AI can feel klutzy and be challenging to use and understand. RESTful APIs are for consumers. The name and structure of URIs should convey meaning to those consumers. It’s often difficult to know what the data boundaries should be, but with the understanding of your data, you must likely are equipped to take a stab and what makes sense to return as a representation to your clients. Design for your clients, not for your data.
Pluralization
The commonly-accepted practice is always to use plurals in node names to keep your API URIs consistent across all HTTP methods. The reasoning is that `customers` are collection within the service suite and the ID (e.g., 23223) refers to one of those customers in the collection.
Monitoring
Make sure to add all kinds of monitoring to improve the quality or performance of your API. Data points can be Response Time (P50, P90, P99), Status Codes (5XX, 4XX, etc.), Network Bandwidth, and many more.
Security
1. Authorization / Authentication: Authorization for services is no different than authorization for any application. Ask this question, “Does this principal have the requested permission on the given resource?”
2. CORS: implementing CORS on a server is as simple as sending an additional HTTP header in the response, such as Access-Control-Allow-Origin, Access-Control-Allow-Credentials, etc.
3. TLS: all authentications should use SSL. OAuth2 requires the authorization server and access token credentials to use TLS.
4. Idempotence: an operation that will produce the same results if executed once or multiple times. It may have a different meaning depending on the context in which it applies. In the case of methods or subroutine calls with side effects, for instance, it means that the modified state remains the same after the first call.
5. Input Validation: Validate all input on the server. Accept “known” good input and reject bad input, Protect against SQL and NoSQL injection, Restrict the message size to the exact length of the field, services should only display generic error messages, and many more.
6. Rate limiting: is a strategy for limiting network traffic. It puts a cap on how often someone can repeat an action within a certain timeframe for instance, trying to log into an account.
7. Logging: Make sure you do not accidentally log any personally identifiable information (PII).
With that I conclude this learning; I hope you have learned something new today. Thanks for reading and have a wonderful learning experience in your adventure in tech.