Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a sub-resource or not?

Let's take the following example:

We want to expose company and employee information from a RESTful API.

Company data should be quite simply:

GET api/v1/companies
GET api/v1/companies/{id}

Employees BELONG to a company, but we still want to retrieve them individually as well, so which solution is best:

Solution 1: Using sub-resources

Get all employees for a company:

GET api/v1/companies/{companyId}/employees

Get a specific employee:

GET api/v1/companies/{companyId}/employees/{employeeId}

Solution 2: Using an independent resources

Get all employees for a company:

GET api/v1/employees?companyId={companyId}

Get a specific employee:

GET api/v1/employees/{employeeId}

Both options seem to have their pros and cons.

  • With sub-resources, I may not always have the CompanyId on hand when wanting to retrieve an individual employee.

  • With an independent resource, getting all employees for a company should use the sub-resource approach if we want to be RESTful.

Otherwise, we could use a mix, but this lacks consistency:

Get all employees for a company:

GET api/v1/companies/{companyId}/employees

Get a specific employee:

GET api/v1/employees/{employeeId}

What is the best approach to take in such a situation if we want to stay true to RESTful standards?

like image 971
Dave New Avatar asked Nov 07 '14 06:11

Dave New


2 Answers

For me this sounds like the common many-to-many relationship problem for RESTful services. (see How to handle many-to-many relationships in a RESTful API?)

Your first solution seems good at first but you will have problems whenever you want to access the relation itself.

Instead of returning the employee with the following GET request you should return the relation.

GET api/v1/companies/{companyId}/employees/{employeeId}

If the relation can be identified by 2 keys this solutions seems to be fine. But what happens if the relation is identified by 3+ id's? The URI becomes rather long.

GET api/v1/companies/{companyId}/employees/{employeeId}/categories/{categoryId}

In this case I would come up with a separate resource for the relation:

GET api/v1/company-employees/{id}

The returned model in JSON would look like this:

{
   "id": 1 <- the id of the relation
   "company": {
      "id": 2
   },
   "employee": {
      "id": 3
   },
   "category": {
      "id": 4
   }
}
like image 145
niklr Avatar answered Oct 29 '22 17:10

niklr


I think it would be okay to provide both. If you want the client to browse through the list of companies first, then select a company and then get the list of all employees, the first approach is necessary. If, may be in addition, you want the client to be able to filter employees by name or age, but without knowing the company identifier, you must provide the second approach as well. It depends on what you want the client to do. In my opinion, it would not be necessary to provide the second approach, if clients can only filter employees by company identifier.

like image 43
braunpet Avatar answered Oct 29 '22 17:10

braunpet