Restful API design with composite DTOs - web-services

I get the simple Restful design following one type of object:
GET /users
GET /users/123
POST /users/new
POST /users/1/edit (or PUT)
POST /users/1/delete (or DELETE)
...
Follow a Relationship from a type of object to another:
GET /user/123/company
GET /user/123/roles
POST /user/123/roles/new
…
What about a composite DTO mixing multiple objects in it? For example:
//Listing all users with their companies and primary role
GET /usersWithCompaniesAndPrimaryRoles
//List all companies with users and roles count in each company
GET /companiesWithUsersAndRolesCount
In this case, my API link doesn’t look very clean or Restful to me anymore? I am wondering how I should structure the CRUD of these composite DTOs in a Restful way? Please advise me, or link me to where I can learn how to do that?
Thank you very much.

A Restful design should have such API paths.
Instead, you should use the GET /users URI, and provide query parameters. for example:
GET /users?with_companies=yes
In the Restful, you should not think about URIs as API commands. Try, instead to think about URIs as entities, that you can Get, Insert, change, and delete.
There is no room for other "commands".
That is why, for example,
There shouldn't be POST /users/new API path.
instead, just post to /users.
Another possible RESTfull way is to create a "Query Resource" object using POST, returning "Query Resource ID Number", which will later be used in a separated GET request.
By that you are creating saved queries which can also be efficient for re-querying as well.

Related

Correct approach to creating API endpoints

I'm creating an API in Django Rest Framework and i'm thinking about best approach to provide actions like adding a post to user reading list. Firstly i've done it by GET request, because it was looking most natural and url for example looks like /api/posts/{id}/add_to_reading_list/. Now i recognized that GET should be used only to retrieve data so i've changed it to POST method and now url is looking like /api/posts/add_to_reading_list/. The first thing is that i needed to create new serializer specially to handle this action which accepts only id field, because this endpoint should accept only already created posts. Is it how it should be done? I was thinking about sending whole post object in POST method, but doesn't it a waste of bandwidth when i need only id? It will prevent me of creating a new serializer for this specific case, but i don't think that it is a correct approach.

RESTful API: how to tell whether an object retrieved by GET is editable (e.g, PUT-able) by the current user?

Currently I set up a RESTful API backend using Django and I can list a set of articles by the following GET:
api/articles/
Also, I can get a single article by:
api/article/1/
Each article is owned by a certain user, and one user could have multiple articles of course.
On the frond end side, I present all the articles at loading of the page, and I hope the user who is logged in currently could see the articles that they own in a different style, e.g, outlined by a box, and has a associated "delete" or "edit" button.
This requires me to tell, after the retrieval of the articles, which ones are owned by the current user programmatically. One way of doing this is to check the current user id with the owner id. However I feel this is not a good choice as the user id is the check is done fully on the client side and may be not consistent with the actual server judgement.
Therefore, is there a way, to tell by looking at the response of the GET, (say, let the server return a property "editable=true/false") to get whether the current user could edit(PUT) the resource?
I understand that this could be done at the server side, by attaching such a property manually. However, I am just asking whether there is better/common practice.
I just started learning web development and I am sorry if the question sounds trivial. Thank you!
You can attach propriety manually as you suggested. The advance of this approach is that you dont need any other http request.
Second possibility might be, that your client intentionally request information about endpoint permissions. In this case I would suggest to use OPTIONS HTTP method. You send OPTIONS HTTP request to api/articles/1 and backend returns wanted info. This might be exactly what OPTIONS method and DRF metadata were made for.
http://www.django-rest-framework.org/api-guide/metadata/
I think that this is a very interesting question.
Several options that come to me:
You can add to the GET api/article/1 response a HTTP header with this information i.e. HTTP_METHODS_ALLOWED=PUT,PATH,DELETE. Doing this way helps the API client because it does not need to know anything else. I think that this is not a good approach when more than one entity is returned.
call to OPTIONS api/article/1. Allowed methods for that user on that resource can be returned but notice that, in my opinion, this approach is not very good in terms of performance, because it duplicates the number of requests to the server.
But what if the entity returned also contains information on the owner or it? can, in this case the client know which policy apply and try to figure out it by itself? notice that the policy can be obtained from another endpoint (just one call would be needed) or even with the login response. If your entities do not contain that kind of information, it could be also returned as a HTTP header (like first option above)

REST design - Get a collections of reduced ressource

I have a web service to retrieve the list of my users : /users
My User entity has a lot of attributes (with many relationship such as roles, address, etc) and it begins to be painful to retrieve the whole list.
I want to create a new web service to retrieve a list of a minimal User DTO. This DTO contains only the username, the first name and the last name.
What's your suggestions for this new URI ?
/users-minimal
/users/minimal
/users/func/get-minimal
... ?
If what's changing is merely the representation, you should make that available as a different media-type, not a different URI. For instance, if you have application/vnd.mycompany.user.v1+json for a normal user, you could use application/vnd.mycompany.user-minimal.v1+json for the minimal.
Now, you probably don't use custom media types like the above, and if you are asking about RESTful URIs, you're probably not using HATEOAS either. For those REST-like HTTP APIs, you should probably use a querystring parameter instead. Something like /users?minimal=1 or /users/?fields=username,first_name,last_name.

Survey App Django-Survey Monkey

I am creating a django application for my company, and one of the things that still needs doing is a survey.
At the moment we use SurveyMonkey, but I can't manage to send via api invitations to the surveys(personalized ones like the web page allows, so we know who answered with which answers).
Does anybody know if it's possible to do this with SurveyMonekey api, or if not, any other django app that what I need, or another way to do this?
SurveyMonkey's API is currently read-only and does not allow adding users to email collectors. And option you might consider is pairing SurveyMonkey with MailChimp. MailChimp currently has docs on how to use it with SurveyMonkey here: http://kb.mailchimp.com/article/setting-up-your-surveymonkey-mailchimp-integration/
You could also create something like the MailChimp API in your own application by adding a unique ID to links you send to your respondents by appending ?c=UNIQUEID to the end of a web link collector URI. Then, in your application, you can send any email invitation you like to potential respondents and use the unique ID to correlate users with responses.
You'll need to request the "custom_id" by adding it to the "fields" array in your request to get_respondent_list in order to that unique ID back from SurveyMonkey using the API.

Hierarchical RESTful URL design

I have perused the questions asked about this, but I still don't have a definitive answer.
I have an application and would like to build a RESTful API to expose a subset of information. I have three resources:
users
reports
photos
Users have reports and reports have photos. Photos cannot exist outside of reports and reports cannot exist outside of users.
I have designed the following URLs for my requirements
User login, server responds with token which is sent in the header of all API calls
GET example.com/api/
Get user info
GET example.com/api/users/{username}
Get all user reports
GET example.com/api/users/{username}/reports
Get all photos of a report
GET example.com/api/users/{username}/reports/{report_id}/photos
Add a photo
POST example.com/api/users/{username}/reports/{report_id}/photos
Delete a photo
DELETE example.com/api/users/{username}/reports/{report_id}/photos/{photo_id}
Modify photo description
PUT example.com/api/users/{username}/reports/{report_id}/photos/{photo_id}
Questions
Is it good practice to add a resource id in the URL, i.e. resource/id, or should this rather be added as a query parameter?
Is this method of chaining resources, i.e. resource/id/sub-resource/id/etc., acceptable and good or should I put all my resources at the top level and specify its position with query parameters?
Nothing wrong in this design.But this creates long URL which sometime are difficult to understand and the user of the API needs to know the hierarchy.Moreover the consumer of the API need to write more code in little bit non-standard way(Even though it can be done, but will be little messy). Think this from a different perspective
You have three resources and each has its own identity.So if we refactor the above URI's it will looks like below (I am demonstrating only GET)
User Resource:
Get users list
GET example.com/api/users
Get specific user
GET example.com/api/users/{username}
Report Resource:
Get all reports
GET example.com/api/reports
Get a specific report
GET example.com/api/reports/{report_id}
Photo Resources
All Photos
GET example.com/api/photos
Specific Photo
GET example.com/api/photos/{photo_id}
User All Reports
GET example.com/api/reports?username={userName}
Specific report of a user
GET example.com/api/report?username={userName}&report_id={reportId}
User All Photos
GET example.com/api/photos?username={userName}
User All Photos for a report id (You may not need user Name if report_id is unique irrespective of the user, which will further simplify the URI)
GET example.com/api/photos?username={userName}&report_id={reportId}
All photos of a report
GET example.com/api/photos?report_id={reportId}
This simplifies the understanding and more standard code can be written on the consumer side using this approach.
IMHO you are modelling it well.
Regarding 1 I'd rather go with resource/id rather than query param. But one thing you must have in mind when modelling is the cache mechanism by proxy and so on. So do not forget the headers.
I go for query params for filtering and those sorts.
About the login, the credentials should be in the headers, and no specific resource is needed. Just apply per resource security.
I don't see anything wrong with your scheme.
Most frameworks nowadays use a similar standard for specifying url's (like Django).
In my personal opinion, it makes the URL more readable and a bit nicer for the user.