Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Modern API Development with Spring and Spring Boot

You're reading from   Modern API Development with Spring and Spring Boot Design highly scalable and maintainable APIs with REST, gRPC, GraphQL, and the reactive paradigm

Arrow left icon
Product type Paperback
Published in Jun 2021
Publisher Packt
ISBN-13 9781800562479
Length 582 pages
Edition 1st Edition
Languages
Tools
Concepts
Arrow right icon
Author (1):
Arrow left icon
Sourabh Sharma Sourabh Sharma
Author Profile Icon Sourabh Sharma
Sourabh Sharma
Arrow right icon
View More author details
Toc

Table of Contents (21) Chapters Close

Preface 1. Section 1: RESTful Web Services
2. Chapter 1: RESTful Web Service Fundamentals FREE CHAPTER 3. Chapter 2: Spring Concepts and REST APIs 4. Chapter 3: API Specifications and Implementation 5. Chapter 4: Writing Business Logic for APIs 6. Chapter 5: Asynchronous API Design 7. Section 2: Security, UI, Testing, and Deployment
8. Chapter 6: Security (Authorization and Authentication) 9. Chapter 7: Designing a User Interface 10. Chapter 8: Testing APIs 11. Chapter 9: Deployment of Web Services 12. Section 3: gRPC, Logging, and Monitoring
13. Chapter 10: gRPC Fundamentals 14. Chapter 11: gRPC-based API Development and Testing 15. Chapter 12: Logging and Tracing 16. Section 4: GraphQL
17. Chapter 13: GraphQL Fundamentals 18. Chapter 14: GraphQL API Development and Testing 19. Assessments 20. Other Books You May Enjoy

Best practices for designing REST APIs

It is too early to talk about the best practices for implementing APIs. APIs are designed first and implemented later. Therefore, you'll find design-related best practices mentioned in the next sections. You'll also find best practices for going forward during the course of your REST API implementation.

1. Use nouns and not verbs when naming a resource in the endpoint path

We previously discussed HTTP methods. HTTP methods use verbs. Therefore, it would be redundant to use verbs yourself, and it would make your call look like an RPC endpoint, for example, GET /getlicenses. In REST, we should always use the resource name because, according to REST, you transfer the states and not the instructions.

For example, let's take another look at the GitHub license API that retrieves the available licenses. It is GET /licenses. That is perfect. Let's assume that if you use verbs for this endpoint, then it will be GET /getlicenses. It will still work, but semantically, it doesn't follow REST because it conveys the processing instruction rather than state transfer. Therefore, only use resource names.

However, GitHub's public API only offers read operations on the licenses resource, out of all the CRUD operations. If we need to design the rest of the operations, their paths should look like following:

  • POST /licenses: This is for creating a new license.
  • PATCH /licenses/{license_key}: This is for partial updates. Here, the path has a parameter (that is, an identifier), which makes the path dynamic. Here, the license key is a unique value in the license collection and is being used as an identifier. Each license will have a unique key. This call should make the update in the given license. Please remember that GitHub uses PUT for the replacement of the resource.
  • DELETE /licenses/{license_key}: This is for retrieving license information. You can try this with any license that you receive in the response of the GET /licenses call. One example is GET /licenses/agpl-3.0.

You can see how having a noun in the resource path with the HTTP methods sorts out any ambiguity.

2. Use the plural form for naming the collection resource in the endpoint path

If you observe the GitHub license API, you might find that a resource name is given in the plural form. It is a good practice to use the plural form if the resource represents a collection. Therefore, we can use /licenses instead of /license. A GET call returns the collection of licenses. A style call creates a new license in the existing license collection. For delete and patch calls, a license key is used to identify the specific license.

3. Use hypermedia (HATEOAS)

Hypermedia (that is, links to other resources) makes the REST client's job easier. There are two advantages if you provide explicit URL links in a response. First, the REST client is not required to construct the REST URLs on their own. Second, any upgrade in the endpoint path will be taken care of automatically and this, therefore, makes upgrades easier for clients and developers.

4. Always version your APIs

The versioning of APIs is key for future upgrades. Over time, APIs keep changing, and you may have customers who are still using an older version. Therefore, you need to support multiple versions of APIs.

There are different ways you can version your APIs, as follows:

  • Using headers: The GitHub API uses this approach. You can add an Accept header that tells you which API version should serve the request; for example, consider the following:
    Accept: application/vnd.github.v3+json

    This approach gives you the advantage of setting the default version. If there is no Accept header, it should lead to the default version. However, if a REST client that uses a versioning header is not changed after a recent upgrade of APIs, it may lead to a functionality break. Therefore, it is recommended that you use a versioning header.

  • Using an endpoint path: In this approach, you add a version in the endpoint path itself; for example, https://demo.app/api/v1/persons. Here, v1 denotes that version 1 is being added to the path itself.

    You cannot set default versioning out of the box. However, you can overcome this limitation by using other methods, such as request forwarding. Clients always use the intended versions of the APIs in this approach.

Based on your preferences and views, you can choose either of the preceding approaches for versioning. However, the important point is that you should always use versioning.

5. Nested resources

Consider this very interesting question: how are you going to construct the endpoint for resources that are nested or have a certain relationship? Let's take a look at some examples of customer resources from an e-commerce perspective:

  • GET /customers/1/addresses: This returns the collection of addresses for customer 1.
  • GET /customers/1/addresses/2: This returns the second address of customer 1.
  • POST /customers/1/addresses: This adds a new address to customer 1's addresses.
  • PUT /customers/1/address/2: This replaces the second address of customer 1.
  • PATCH /customers/1/address/2: This partially updates the second address of customer 1.
  • DELETE /customers/1/address/2: This deletes the second address of customer 1.

So far so good. Now, can we can have an altogether separate addresses resource endpoint (GET /addresses/2)? It makes sense, and you can do that if there exists a relationship that requires it; for example, orders and payments. Instead of /orders/1/payments/1, you might prefer a separate /payments/1 endpoint. In the microservice world, this makes more sense; for instance, you would have two separate RESTful web services for both orders and payments.

Now, if you combine this approach with hypermedia, it makes things easier. When you make a REST API request to customer 1, it will provide the customer 1 data and address links as hypermedia (that is, links). The same applies to orders. For orders, the payment link will be available as hypermedia.

However, in some cases, you might wish to have a complete response in a single request rather than using the hypermedia-provided URLs to fetch the related resource. This reduces your web hits. However, there is no thumb rule. For a flag operation, it makes sense to use the nested endpoint approach; for example, PUT /gist/2/star (which adds a star) and DELETE /gist/2/star (which undoes the star) in the case of the GitHub API.

Additionally, in some scenarios, you might not find a suitable resource name when multiple resources are involved, for example, in a search operation. In that case, you should use a direct /search endpoint. This is an exception.

6. Secure APIs

Securing your API is another expectation that requires diligent attention. Here are some recommendations:

  • Always use HTTPS for encrypted communication.
  • Always look for OWASP's top API security threats and vulnerabilities. These can be found on their website (https://owasp.org/www-project-api-security/) or the GitHub repository (https://github.com/OWASP/API-Security).
  • Secure REST APIs should have authentication in place. REST APIs are stateless; therefore, REST APIs should not use cookies or sessions. Instead, these should be secure using JWT or OAuth 2.0-based tokens.

7. Documentation

Documentation should be easily accessible and up to date with the latest implementation with their respective versioning. It is always good to provide sample code and examples. It makes the developer's integration job easier.

A change log or a release log should list all of the impacted libraries, and if some APIs are deprecated, then replacement APIs or workarounds should be elaborated on inside the documentation.

8. Status codes

You might have already learned about status code in the Exploring HTTP methods and status codes section. Please follow the same guidelines discussed there.

9. Caching

HTTP already provides the caching mechanism. You just have to provide additional headers in the REST API response. Then, the REST client makes use of the validation to make sure whether to make a call or use the cached response. There are two ways to do it:

  • ETag: ETag is a special header value that contains the hash or checksum value of the resource representation (that is, the response object). This value must change with respect to the response representation. It will remain the same if the resource response doesn't change.

    Now, the client can send a request with another header field, called If-None-Match, which contains the ETag value. When the server receives this request and finds that the hash or checksum value of the resource representation value is different from If-None-Match, only then should it return the response with a new representation and this hash value in the ETag header. If it finds them to be equal, then the server should simply respond with a 304 (Not Modified) status code.

  • Last-Modified: This approach is identical to the ETag way. Instead of using the hash or checksum, it uses the timestamp value in RFC-1123 format (Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT). It is less accurate than ETag and should only be used for the falling mechanism.

    Here, the client sends the If-Modified-Since header with the value received in the Last-Modified response header. The server compares the resource-modified timestamp value with the If-Modified-Since header value and sends a 304 status if there is a match; otherwise, it sends the response with a new Last-Modified header.

10. Rate limit

This is important if you want to prevent the overuse of APIs. The HTTP status code 429 Too Many Requests is used when the rate limit goes over. Currently, there is no standard to communicate any warning to the client before the rate limit goes over. However, there is a popular way to communicate about it using response headers; these include the following:

  • X-Ratelimit-Limit: The number of allowed requests in the current period
  • X-Ratelimit-Remaining: The number of remaining requests in the current period
  • X-Ratelimit-Reset: The number of seconds left in the current period
  • X-Ratelimit-Used: The number of requests used in the current period

You can check the headers sent by the GitHub APIs. For example, they could look similar to the following:

  • X-Ratelimit-Limit: 60
  • X-Ratelimit-Remaining: 55
  • X-Ratelimit-Reset: 1601299930
  • X-Ratelimit-Used: 5

So far, we have discussed various concepts related to REST. Next, we will next move on to discuss our sample app.

You have been reading a chapter from
Modern API Development with Spring and Spring Boot
Published in: Jun 2021
Publisher: Packt
ISBN-13: 9781800562479
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €18.99/month. Cancel anytime