Routing strategy for a restful service - rest

We're working on a restservice using Web-API and breaking our heads on what routing strategy to follow.
We got some resources:
Grades
Messages
Homework
(As a side note: We plan on using Hateoas to have linking between resources. )
We're considering Controller[Action][Id] resulting in
API\Grade[?personid] (GET/POST)
API\Grade\{id}[?personid] (GET/PUT/DELETE)
API\Grade\Lastgrades\{days}[?personid] (GET)
Or using a context
API\Student\Grade (GET)
API\Student\Grade\{id} (GET)
API\Student\Grade\Lastgrades\{days} (GET)
AND
API\Parent\Student\{id}\Grade (GET)
API\Parent\Student\{id}\Grade\{id} (GET)
API\Parent\Student\{id}\Grade\Lastgrades\{days} (GET)
AND
API\Teacher\Student\{id}\Grade (GET/POST)
API\Teacher\Student\{id}\Grade\{id} (GET/PUT/DELETE)
API\Teacher\Student\{id}\Grade\Lastgrades\{days} (GET)
Is there a good reason to use one strategy over the other?

In your 1st option, the focus is on grades, which is the resource that the API is designed to manage.
In your 2nd option, by just looking at the URL patterns, there are few more resources involved, like Teachers and Students.
Without really knowing your business use-cases, the answer to your question is more have do with the initial scope of your API .
If it is focusing on Grades but not Teachers nor Students, then you can just provide API to manage the ‘grades’ resources, meaning your option-1.
Later if you need to also manage “Teachers and Students”, you can add the options-2 to your implementation.
They don’t necessary to be mutually exclusive.
Update-1
The role/context should not be part of the URL. It should be handled separately like once each role is logged into the system; there should be already ways to associate with the role in the backend for example via session etc.
The URL design focus should be on the resources, in this case the Grades. Also since logically, Grades should be associated with Students or even associated with a class that a student took, I will suggest designing it like in the following
/api/v1/grades/students/[student-id]/
OR
/api/v1/students/[student-id]/grades/
OR
/api/v1/students/[student-id]/classes/[class-id]/grades/
These are all acceptable solutions and depending on your business use-cases, one may be better than other.
The roles only come to play as what CRUD operations can act on these resources, like Teacher can POST/PUT/GET on
/api/v1/students/[student-id]/grades/
But Students/Parents can only do GET on
/api/v1/students/[student-id]/grades/
You still need to consider the role/context as part of your overall design and perhaps how the URL design may make more sense depending on how you want to support the operations that each role will use the URL to manage the resources. But the 'context/role' should not be part of the URL.

Related

How should I design a REST API

I'm thinking about a REST API design. There are several tables in my database. For example Customer and Order.
Of course - each Order has its Customer (and every customer can have many Orders).
I've decided to provide such an interface
/api/v1/Customers/ -- get list of Customers, add new Customer
/api/v1/Customers/:id: -- get Customer with id=:id:
/api/v1/Orders/ -- get list of Orders, add new Order
/api/v1/Orders/:id: -- get Order with id=:id:
It works flawlessly. But my frontend has to display a list of orders with customer names. With this interface, I will have to make a single call to /api/v1/Orders/ and then another call to /api/v1/Customer/:id: for each record from the previous call. Or perform two calls to /api/v1/Orders/ and /api/v1/Customers/ and combine them on the frontend side.
It looks like overkill, this kind of operation should be done at the database level. But how can/should I provide an appropriate interface?
/api/v1/OrdersWithCustomers
/api/v1/OrdersWithCustomers/:id:
Seems weir. Is it a right way to go
There's no rule that says you cannot "extend" the data being returned from a REST API call. So instead of returning "just" the Order entity (as stored in the backend), you could of course return an OrderResponseDTO which includes all (revelant) fields of the Order entity - plus some from the Customer entity that might are relevant in your use case.
The data model for your REST API does not have to be an exact 1:1 match to your underlying database schema - it does give you the freedom to leave out some fields, or add some additional information that the consumers of your API will find helpful.
Great question, and any API design will tend to hit pragmatic reality at some point like this.
One option is to include a larger object graph for each resource (ie include the customer linked to each order) but use filter query parameters to allow users to specify what properties they require or don't require.
Personally I think that request parameters on a restful GET are fine for either search semantics when retrieving a list of resources, or filtering what is presented for each resource as in this case
Another option for your use case might be to look into a GraphQL approach.
How would you do it on the web?
You've got a web site, and that website serves documents about Customers, and documents about Orders. But your clients aren't happy, because its too much boring, mistake-prone work to aggregate information in the two kinds of documents.
Can we please have a document, they ask, with the boring work already done?
And so you generate a bunch of these new reports, and stick them on your web server, and create links to make it easier to navigate between related documents. TA-DA.
A "REST-API" is a facade that makes your information look and act like a web site. The fact that you are generating your representations from a database is an implementation details, deliberately hidden behind the "uniform interface".

How to handle name conflict with action in RESTful API

RESTful API should be focused on resource and not action.
However, when implementing RESTful on HTTP, due to the limited expressiveness of the HTTP methods, people add [action] to the end of the URL.
e.g.:
http://rebilly.github.io/ReDoc/#operation/findPetsByStatus
https://developers.google.com/drive/api/v3/reference/
(DELETE /files/trash and GET /files/generateIds)
For API that the ID is defined by the user, the above design would lead to conflicts.
i.e. user creating a pet findPetsByStatus or a file trash or generateIds.
The API designer cannot prevent this from happening because we cannot foresee the future. i.e. we can't reserves all keywords that might be used as actions because the product evolves and changes over time.
Under this circumstances, how to design an API so we won't run into such problem?
I would like to follow OpenAPI spec but they disallow API with /files?action=<someAction>
Under this circumstances, how to design an API so we won't run into such problem?
Change the stem; restrict the identifiers with user provided spellings to a different part of your endpoint hierarchy than the operations where you would need to worry about reserved words.
That is to say, you treat your URI space as a bunch of partitioned name spaces; you let your users customize the spellings in one name space, you put your api operations in another. Ta-Da.
/b9d97060-d4db-4b20-a654-22bb0653db69/pets
/08f9a7c2-353b-484d-9e87-56acca4e5a57/pets
See? No conflicts.
If somebody insists that all pet endpoints must be located under /pets, then just invert the ordering
/pets/b9d97060-d4db-4b20-a654-22bb0653db69
/pets/08f9a7c2-353b-484d-9e87-56acca4e5a57
Another possibility would be to host pet management on a different host than your pet utilities.
http://search.example.org/pets
http://api.example.org/pets
In a spelling argument, you might be able to find some support in the ubiquitous language of your domain. For example, in a setting where you speak of consumers registering their pets, you could argue
/pets/registry
/pets/forms
separates the documents that describe the registered pets from the forms used to do interesting things with the registered pets.
/pets/registry/findPetsByStatus <-- the dog belonging to [Bobby Tables][1]
/pets/forms/findPetsByStatus <-- the documents used to integrate with the pets service
Don't get too caught up in the spelling debate -- loading a /findPetsByStatusForm and submitting it to get a /findPetsByStatusReport may pass the noun test, but it doesn't improve the quality of the API.

REST URL Design for One to Many and Many to Many Relationships

Your backend has two Models:
One Company to Many Employees.
You want to accomplish the following:
Get all Companies
Get a Company by ID
Get all Employees for a Company
Get all Employees
Get a Employee by ID
What is the best practice for handling the REST URLs when your models have 1:M relationships? This is what I have thought of so far:
/companies/
/companies/<company_id>/
/companies/<company_id>/employees/
/employees/
/employees/id/<employee_id>/
Now let's pretend One Company has Many Models. What is the best name to use for "Adding an employee to a Company" ? I can think of several alternatives:
Using GET:
/companies/<company_id>/add-employee/<employee_id>/
/employees/<employee_id/add-company/<company_id>/
Using POST:
/companies/add-employee/
/employees/add-company/
The URIs look fine to me, except maybe the last one, that does not need an additional "id" in the path. Also, I prefer singular forms of words, but that is just me perhaps:
/company/
/company/<company_id>/
/company/<company_id>/employee/
/employee/
/employee/<employee_id>/
The URIs do not matter that much actually, and can be changed at any point later in time when done properly. That is, all the URIs are linked to, instead of hardcoded into the client.
As far as adding an employee, I would perhaps use the same URIs defined above, and the PUT method:
PUT /employee/123
With some representation of an employee. I would prefer the PUT because it is idempotent. This means, if the operation seems to fail (timeout, network error occurs, whatever) the operation can be repeated without checking whether the previous one "really" failed on the server or not. The PUT requires some additional work on the server side, and some additional work to properly link to (such as forms), but offers a more robust design.
As an alternative you can use
POST /employee
With the employee representation as body. This does not offer any guarantees, but it is easier to implement.
Do not use GET to add an employee (or anything for that matter). This would go against the HTTP Specification for the GET method, which states that it should be a pure information retrieval method.

Api naming in microservices design

Let's say that there are two microservices representing the resources orders(/orders) and customers(/customers). My requirement is to get all the orders made by a customer.
Had it been a monolithic application, I would have modeled my uri as /customers/{id}/orders. This would have hit the customers resource and made an in-memory service call to get the corresponding orders.
Now, in case of microservices, this isn't possible. So, is the only way to get the orders is to make a remote service call or is there a better way of doing it?
Can we create another resource with the representation /ordersByCustomers/{customerid}?
You can pass some query parameters as filters (this is the most common way I've seen). For example
/orders?customerId=123
I think that's quite clear, that you want to retrieve all customer orders filtered by customer id. In the same way you can add pagination or other filters.
The important thing to remember is that you want the order resource, so the URL should remain the same. I'm mentioning this, because this has been the most difficult thing for me to change... to think about resources rather than remote calls.
In general you should beware of using endpoint that are more or less similar to the one you suggested:
/ordersByCustomers/{customerid}
Why? Because this is not RESTful in general (even in microservices environment) and make the API difficult to understand and you by the consumers. What if you need orderByWhatever? Will you be introducing new endpoint every single time you need a new set of data? Try to avoid so opinionated endpoints.
What #Augutsto suggested is fully correct. If you're afraid of having a complicated logic in GET request this is the situation where you can break REST rules. I mean introducing:
POST /orders/filter/
Where all the filtering logic will be passed in requests body - so it's easier to carry complicated logic as well.

RESTful API subresource pattern

In designing a RESTful API, the following call gives us basic information on user 123 (first name, last name, etc):
/api/users/123
We have a lot of information on users so we make additional calls to get subresources on a user like their cart:
/api/users/123/cart
For an admin page we would like to see all the cart information for all the users. A big table listing each user and some details about their cart. Obviously we don't want to make a separate API call for each user (tons of requests). How would this be done using RESTful API patterns?
/api/carts/users came to mind but then you'd in theory have 2 ways to get a specific user's cart by going /api/carts/users/123.
This is generally solved by adding a deref capability to your REST server. Assuming the response from your user looks like:
{
...
cartId: "12345",
...
}
you could add a simple dereference by passing in the query string "&deref=cart" (or however you setup your syntax.)
This still leaves the problem of making a request per user. I'd posit there are two ways to generally do this. The first would be with a multiget type of resource (see [1] for an example). The problem with this approach is you must know all of the IDs and handle paging yourself. The second (which I believe is better) is to implement an index endpoint to your user resource. Indexing allows you to query a resource (generally via a query string such as firstName=X or whatever else you want to sort on.) Then you should implement basic paging so you're not passing around massive amounts of data. There are tons of examples of paging, but the simplest would be to specify a number (count=20) a start token (since=X) and a sort order (sort=-createdAt).
These implementations allow you to then ask for all users and their carts by iterating on the index endpoint. You might find this helpful as a starting point for paging [2].
[1] - How to construct a REST API that takes an array of id's for the resources
[2] - Pagination in a REST web application
For some reason I was under the assumption that having 2 URIs to the same resource was a bad thing. In my situation /api/users/123/cart and /api/carts/users/123 would return the same data. Through more research I've learned from countless sources that it's acceptable to have multiple URIs to the same resource if it makes sense to the end user.
In my case I probably wont expose /api/carts/users/123, but I'm planning on using /api/carts/users with some query parameters to return a subset of carts in the system. Similarly, I'm going to have /api/carts/orgs to search org carts.
A really good site I found with examples and clear explanations was the REST API Tutorial. I hope this helps others with planning their API URIs.