How to Design URL to REST Resource

In this post, we will learn how to design a URL for REST API and the best practices for designing a URL for a resource. Finally, we will see case studies of real-world examples.

In the previous post, we learned How to Identify REST Resources. Now, it's time to assign a URL to the identified resource.

How to Design URL to REST Resource

Let's discuss this in-depth with examples and case studies.

Basically, the URL is assigned to the extracted resource to identify it. The following formats are recommended for the URL:

http(s)://{Domain name (:Port number)}/{A value indicating REST API}/{API version}/{path for identifying a resource}
http(s)://{Domain name indicating REST API(:Port number)}/{API version}/{path for identifying a resource}
Typical examples are:
Let's discuss each part of the URL in depth.

Assigning a URL that indicates the API as REST API

It is recommended to include API within the URL domain or path to clearly indicate that the URL is intended for RESTful Web Service (REST API). Typically, the URL looks like this:

Assigning a URL for identifying the API version

You can version your API by adding a version number to the URL, which can be especially useful when introducing non-backwards-compatible changes:
Typically, the URL format with version looks like this:{API version}/{path for identifying a resource}{API version}/{path for identifying a resource}

Assigning a path for identifying resource

RESTful URIs should not have verbs in them. The action should be inferred from the HTTP method (GET, POST, PUT, DELETE, etc.): 
  • GET /orders - Retrieves a list of orders. 
  • POST /orders - Creates a new order. 
You should avoid:
  •  /getOrders 
  • /createOrder
Use Sub-resources for Relations: If a resource is related to another resource, you can use sub-resources. 
  • /users/123/orders - Retrieves a list of orders for user with ID 123.

RESTful URL Design Cheat Sheet

1. Use Nouns, Not Verbs

  • /users
  • /getUser

2. Always Use Plural Nouns

  • /books
  • /book

3. Avoid CRUD Terms

  • GET /orders (for retrieving orders)
  • /getAllOrders

4. Identify Unique Resources with IDs

  • /employees/45 (Employee with ID 45)
  • /employees?employeeId=45

5. Sub-resources for Nested Relationships

  • /departments/3/employees (Employees in department 3)
  • /employeesInDepartment/3

6. Use Query Parameters for Filters, Sorts, and Pagination

  • /books?author=Rowling&sort=title
  • /booksByRowlingSortedByTitle

7. Implement Versioning (optional but useful)

  • /v1/products
  • /productsVersion1

8. Maintain Consistent Naming Conventions

  • Choose either camelCase (/userGroups) or snake_case (/user_groups), but don't mix.

9. Stick to Standard HTTP Methods

  • POST to create, GET to read, PUT to update (or create), DELETE to delete.

10. Use HTTP Status Codes to Indicate Results

  • 200 OK, 201 Created, 400 Bad Request, 404 Not Found, etc.

Case Study 1

Let's understand how to design a URL for REST API using a real-world example. Let’s write a few APIs for companies that have some employees to understand more. /getAllEmployees is an API that will respond with the list of employees. A few more APIs around a Company will look as follows:
  • /addNewEmployee 
  • /updateEmployee 
  • /deleteEmployee 
  • /deleteAllEmployees 
  • /promoteEmployee 
  • /promoteAllEmployees 
And there will be tons of other API endpoints like these for different operations. All of those will contain many redundant actions. Hence, all these API endpoints would be burdensome to maintain, when API count increases.

What is wrong?

The URL should only contain resources(nouns), not actions or verbs. The API path /addNewEmployee contains the action addNew along with the resource name Employee.

What is the correct way?

/companies endpoint is a good example that contains no action. But the question is how do we tell the server about the actions to be performed on companies to resource viz. whether to add, delete or update?

This is where the HTTP methods (GET, POST, DELETE, PUT), also called verbs, play the role.

The resource should always be plural in the API endpoint, and if we want to access one instance of the resource, we can always pass the id in the URL.
  • method GET path /companies should get the list of all companies
  • method GET path /companies/34 should get the detail of company 34
  • method DELETE path /companies/34 should delete company 34
In a few other use cases, if we have resources under a resource, e.g Employees of a Company, then few of the sample API endpoints would be:
  • method: GET path: /companies/3/employees should get the list of all employees from company 3
  • method: GET path: /companies/3/employees/45 should get the details of employee 45, which belongs to company 3
  • method: DELETE path: /companies/3/employees/45 should delete employee 45, which belongs to company 3
  • method: POST path: /companies should create a new company and return the details of the new company created

Case Study 2

Let's practice writing URLs for different resources extracted from domain information. Consider messages and tickets in HelpDesk applications.

If a relation can only exist within another resource, RESTful principles provide useful guidance. These messages can be logically mapped to the /tickets endpoint as follows:
  • GET /tickets/12/messages - Retrieves a list of messages for ticket #12 
  • GET /tickets/12/messages/5 - Retrieves message #5 for ticket #12 
  • POST /tickets/12/messages - Creates a new message in ticket #12 
  • PUT /tickets/12/messages/5 - Updates message #5 for ticket #12 
  • PATCH /tickets/12/messages/5 - Partially updates message #5 for ticket #12 
  • DELETE /tickets/12/messages/5 - Deletes message #5 for ticket #12 

Case Study 3

Examples from twitter API doc.
  • Curate a collection of Tweets 
  • GET collections/entries 
  • GET collections/list 
  • GET collections/show 
  • POST collections/create 
  • POST collections/destroy 
  • POST collections/entries/add 
  • POST collections/entries/curate 
  • POST collections/entries/move 
  • POST collections/entries/remove 
  • POST collections/update 
Look at some widely used APIs for your reference: