What is the best practice to get related/nested data from REST API? - rest

For example: We have a User model, which in turn has several Company entities. I see 2 solutions:
1) Classical. Make an API like:
/users/
/users/3/
/users/3/companies/
and issue /users or companies request separately. However, if we need to have both user and his/her companies information in one view (on Angular2) - we need to send 2 requests to the server.
2) Put the related/nested data inside the level-1 object model. In request:
/users/3/
the server will provide information about the User, together with his Companies. In this case we get all information for 1 request. But again, the company has an unlimited number of Storage entities. What if they are required in one separate view?
I'm more inclined to the first option, but I'm confused by the description of the REST style: "The view must fully represent the resource." Satisfaction of this requirement can lead to a partition of the resource into child resources and, accordingly, to smaller representations. "
Please, help with advice, I doubt in connection with the lack of experience what decision will be correct in this case. Oh yes, I forgot, Backend on Django (Python) using Django-Rest-Framework - All this is a SaaS for ~ 1000 users.

Approach 1 is an an ideal approach for REST. But when it comes to designing APIs for the displaying information on the UI it involves much more than just partitioning the APIs as per resources.
So I would suggest including the Company information in the User API. But as you suggested Company object can have very large list of Storage objects, in this case I would recommend including only the necessary and sufficient fields of Company model into User API. So that you will be able to render one view. And then later when user expands the Company section then you can pull the left-over fields from /company/<id> API.
This way you will have lesser API calls for the hits where user doesn't look for Company details and your API will be light weight as well.

Related

REST API for UI - One General Endpoint vs Endpoint per Component

Let’s assume we have two micro-services: companies API and accounts API.
We also have a dashboard that displays some data and visualizations about accounts.
The dashboard includes three widgets (for simplification):
Widget 1 - A table of accounts filtered by some criteria, for example, shows only pending accounts. It also displays a few columns related to the account's company properties.
Widget 2 - A piechart that displays a breakdown of accounts by one of the account’s properties.
Widget 3 - Another chart that shows a breakdown of the accounts by a company.
Theoretically, all of the widgets in the dashboard display data about the same entity - accounts.
Now, I would like to ask about two approaches for fetching and displaying the accounts in the UI:
The general REST endpoint approach
Create one general endpoint for fetching accounts.
Create one general endpoint for fetching companies.
Fetch all of the accounts once the user enters the page.
Fetch all of the companies once the user enters the page.
Let each widget manipulate, filter, and join data based on its needs.
Most of the logic lies in the frontend.
The REST endpoint per widget approach
Create an endpoint per widget that returns all the relevant data for a specific widget, already filtered, manipulated, and joined for the widget needs.
Each widget calls its endpoint and displays the data.
Most of the logic lies in the backend.
My questions are:
What are the pros and cons of each approach?
In which case would you choose one way over the other?
Are there any other ideas for addressing this use case?
Here are my ideas around this:
If you create one general endpoint per entity, then the frontend workload depends on the amount of data you get from the backend (number of accounts / companies). If you have a limit on those entities (say like max 10 accounts), then it shouldn't be an issue. If not, then it might be problematic (over time) to go on that path.
One scenario where I would consider one endpoint per entity is if you have other components (more important) which are consuming data from this REST API, and they need to get data in this way. But even so, I would think twice if this is really necessary.
AFAIK, the best practice around UI data flows is that you should do as much work as you can on the backend, where you have control on the resources and you have room for optimizations.
One idea that you can consider is to think about a way to store the data more efficiently (already prepared for the view), to minimize the backend work.

RESTful API Design based on the RBAC model

The problem to face lies in the design of a RESTful API that can manage requests from multiple roles in an RBAC-based solution.
Currently we have different resources that can be accessed from different users, which can have one or more roles grouped according to their privileges.
The API we're trying to define must be as clear as possible to the client but without the overhead of adding additional metadata to the URL that could damage and even conflict with the REST practices and definitions. Therefore, we must avoid at all costs include information about the roles inside the URL. The plan is to use JWT tokens that carry in their payloads the info needed to know which permissions has the user making the request.
Having raised our current situation, let's provide an example and state the problem to solve:
Suppose we have * financiers * and * providers * as users with some roles who both want to access ** attentions ** (our resource). Should we add before the resource ** attentions ** information about the * user * whose trying to access the resource?
The endpoints in that case should be defined (as an example) as:
https://example.com/api/v1/financiers/:id/attentions
https://example.com/api/v1/providers/:id/attentions
This way we're attempting to inform the respective controllers that we want the ** attentions ** for that specific role / user which are, in some way, a sub-resource of them.
On the other hand, we could simply implement a much simpler endpoint as follows:
https://example.com/api/v1/attentions
The logic about which attentions return from the database should be now implemented in an unique method that must handle this two roles (and potentially new ones that could come up in the following features). All the information needed must be obtained from the payload from the token, exposing a much more generic API and freeing the web client from the responsibility of which endpoint call depending on the role.
I want to highlight that the attentions are managed in a Microservices Architecture and, hence, the logic to retrieve them is gathered in a single service. The cost of the API Gateway to route the two (and potentially more) of the endpoints from the first solution is a variable not to discard in our specific situation.
Having exposed our current situation:
Which we'll be the best approach to handle this issue?
Is there another alternative not contemplated that could ease the role management and provide a clean API to expose to the client?
In the second solution, is correct to return only the attentions accessible to that specific user based on the roles that it has? Isn't it counterintuitive to access an endpoint and only get some of the resources from that collection (and not all) based on its role?
I hope that someone could clarify the approach we're taking as there are little and none literature that I've found regarding this issue.
There there are multiple solutions for such kind of filtration, and developer have to select one depending on given situation.
As per my experience I can list following.
Structure
When data can't be accessed directly and developer has to use a relation (i.e a table JOIN). In that case URL have to include both the main and sub entities. Before going with this approach a good check is to ask, if the same URL can be used with POST ?
Example
If we have to fetch list of roles assigned to a specific user or want to assign additional roles then we can use
GET users/:uid/roles
POST users/:uid/roles
Security
With Multi-tenant systems where each user can have his/her private resources, i.e other users are prohibited from accessing those resources. Developer should save tenancy information and to filter the resources according to current authentication, without bothering client or requiring any additional info in URL
Example
Phone album of the user
GET photos
POST photos
Search
If it is not security or structure related but client still want to filter the result set depending on his scenario. then developer should use query-string for the filtration.
Example
Client have to fetch messages from his/her inbox or outbox or want messages which are not yet read. or he/she want to search his/her inbox
GET messages?folder=inbox
GET messages?folder=inbox&status=unread
GET messages?search=nasir

REST API design: one endpoint with if/else logic or two separate role based endpoints

I have an API design/versioning conundrum.
Let's say I have an endpoint /api/customers which GETs all customers (ignore pagination). There's a twist though: if a regular user accesses this endpoint, they will only get the customers created by that user and no one else (I can check the access token and the sub field to determine who sent the request). Other usecase: if an admin accesses this endpoint, they should get ALL customers, regardless of who acquired them.
Now my question is from an API design perspective: is it better to have an if/else role check within the API controller itself to determine do I return ALL (admin) customers or specific (user) customers, OR should I differentiate between endpoints for the user and admin? I.e. admin only endpoint for all customers would be /api/admin/customers and regular users can still access their /api/customers?
In REST, it is normal to have multiple resources that share the same representations.
For example, the "authors' preferred version" of an academic paper is a mapping whose value changes over time, whereas a mapping to "the paper published in the proceedings of conference X" is static. These are two distinct resources, even if they both map to the same value at some point in time. The distinction is necessary so that both resources can be identified and referenced independently. A similar example from software engineering is the separate identification of a version-controlled source code file when referring to the "latest revision", "revision number 1.2.7", or "revision included with the Orange release." -- Fielding, 2000
It is perfectly consistent with that approach that you might have one resource for "all users", and another resource for "users created by Bob".
Where things get twisty is the case where you want to use the same resource identifier to provide different representations. That is, when Alice looks at "users created by me", she sees "users created by Alice", and when Bob looks at "users created by me", he sees "users created by Bob".
One possibility is to have "users created by me" redirect to the appropriate resource. It works, for values of "works" that permit extra round trips when the destination resource isn't already in the local cache.
In HTTP/2, server push may spare you some of that round trip pain.
The rules for shared caches should protect you from sending Alice's view of the "me" resource to Bob, and vice versa, but it is useful to be aware of the meanings of the various headers so that you don't inadvertently disable that protection.
Having different resources can be a problem in some "read your own writes" settings, because the caches won't know that an unsafe request has invalidated both resources. Bob creates a new user via a POST to "users created by me", and the corresponding cache entry is invalidated... but "all users" is a different cache key, and does not get invalidated. So if Bob looks at the all users view, he may see a previously cached copy without the changes that he just saw in his own view.
In some cases, it can make sense to consider sub-resources.
/api/customers
/api/customers#created-by-Alice
/api/customers#created-by-Bob
But if you are trying to reduce the amount of irrelevant data being exchanged, then that's not a good fit.
It should be same endpoint. Otherwise, each front-end which calling your API must have the same logic to determine the role and endpoint mapping.
It depends on your project.
If there's only 2 cases as you mentioned
only get customers created by that user for regular users
get all customers for admin users
then, it'd be better to use 1 endpoint by adding middleware to check current user role.
If you're plan to extend your project.
e.g. if admin users are also needed to get the customers created by that user, it'd better to create 2 endpoint. one for all customers, another one for current user's customers. like - api/customers/all, api/customers/me
I think /api/customers is fine for the cases mentioned. It's analogous to a web page request to index.html returning different content to different users.
If you want to extend it (e.g. Alice requesting Bob's list), you could support optional query params:
/api/customers?accessibleTo=bob
/api/customers?createdBy=bob
This would likely require an authorization check (Does Alice have access to Bob's list?), returning 403 (or 404, depending on your philosophy) when not authorized.
Also don't forget about caching. Avoid the possibility that two requests to the same URL (/api/customers) for different users will result in one user getting the other's list.

REST API for multiple consumers

For exmaple: We have a REST API which provides data for multiple consumers. The most case is like: Frontend (accessable for everyone), admin/management (for admins only), mobile app.
These ones differs in the response data which the REST API delivers. For example, in the admin request, the API should respond the email of the user. In the frontend not. Or the mobile app, shouldnt receive unnecessary data, which are not displayed in the views.
My idea was to set adapters in front of the REST API, but this won't work, if you don't have multiple domains available (e.g. api.xyz.com, api-manage.xyz.com).
I think this is a common way, which most of the app needs. I don't want to build multiple APIs to cover this case.
Is there any way on the application side, for example with middleware? Or I know there is a role based approach, but I dont think, this is enought abstract, because the role doesnt decide which device it is.
There is a little solution:
Role based decision which fields the user can be retrieve. Additionally the consumer has to put a header, or a queryparam like "frontend", "admin", "mobile", to identify which data will be returned. This is independent of the "which the user is able". It's just for optimization.
Are there any other solutions?
Your API should not know about your clients but it should offer the possibility for the clients to do what they want/need. Let's say you need to display a list of product with details. On the desktop you might bring 100 products but in mobile only 10. So the api need to provide a configurable paging. Also in the desktop you might get more information than on mobile. So here if you have an entity product, in the desktop you will get all the fields( multiple attributes for example) but for the mobile you get only the name and one attribute (for example the price) to minimize the payload size.
So the API need to be generic but give clients possibility to use it based on their needs.

REST API Design: When should we use association in Uri for the resources?

We have simple e-commerce website where we have several products. Currently, each product has "Place order" button.
When user clicks on this button, we show user a form to fill Name, Mobile number and address. We don't support any monetary transaction. Once user fills this form, the order is saved to database. The order table has OrderId, ProductId, UserName, UserMobile.
We are designing API to save the user order. Should we have association b/w product and order while designing this?
For example URI to save the user order should be like:
POST /api/products/1/lead/ - The request body has user information i.e. name,mobile,address. OR
POST /api/lead/ - The request body has "PRODUCT ID" and user information i.e. name,mobile,address.
I am confused whether productId should be in request URI or in the request body? How do we make such decision?
Given that
you're first navigating to a product, before actually placing the order
the product id has nothing in common with the UserInformation model that you're posting
I'd go with the first option: POST /api/products/1/lead/
I would always go with a more shallow route for representing resources, just for the sake of simplicity. No, a nested route isn't complicated or anything, but I've seen nesting go really far. So I would keep it as shallow as possible unless...
1) You plan on having more than one thing that can have a lead. For example, you can have a lead on a product:
api/products/1/lead
or a lead on a managed service that you all provide or something (I'm reaching right now):
api/managed_services/2/lead
You could pass that info in the body always, but I imagine it would become a little cumbersome to base what resource to create based on what properties were defined in the json.
2) You plan on breaking out that route and having it go to a different service eventually. Maybe this app will have to scale substantially and a ton of users will be hitting this route moreso than any other endpoint in the system. It's a lot easier to redirect all requests to a different microservice based on the url starting with api/products than it would be redirect based on the request body.
But honestly, I don't think it matters too much. As long as it's easy for your clients to consume.