Dependent resources in a RESTful API - django

For the last few days I’ve been looking into the world of REST frameworks (the Django rest framework in specific).
The concept of a RESTful API seems pretty straight forward but there is one thing I’ve been wondering about.
Let say I have the following data structure:
Group
ID
GroupName
User
ID
UserName
GroupUser
userId
groupId
When working with dependent resources I’ve been wondering how you would return and create these objects.
In the case described above I can think of two ways to create a user and add the user to one or more groups:
Option 1:
I send a POST request with the UserName to the server.
Followed by one or multiple POST request adding the user to one or more groups. Adding non existing groups in separate POST requests.
Or, options 2:
I create the user and add all the groups in the request and let my serialiser take care of any of the groups that have not been created yet.
The second option sounds more efficient but request can probably start looking rather strange since some of the groups will be defined by an ID (know groups) and some by a name (non-existing groups). The main thing with this solution is that the serialisers will be rather different from the models.
My question basically boils down to the following:
In a RESTful API how should you deal with dependent resources?

It becomes pretty obvious if you try naming the things.
Option one would be something like:
// creating the user
POST /user
// adding users to the group
POST /usergroup
POST /usergroup
// adding a new group
POST /group
POST /usergroup
Option two would be more like:
POST /CreateUserAndGroupMappingCreatingMissingGroups
Option two is a RPC model, not a restful model.
REST is about nouns: if you can't name the thing you are posting to, or if that thing looks like a verb, then you haven't built a very restful service.
There is nothing wrong with a RPC service; just be aware of what you are creating.

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.

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.

Adding groups to django app

I'd like to add the capability for users to create their own groups and invite others to join the group (or leave the group) or for users to request access to a group to a django app.
The group in this case is basically a pool of potential players for a football match, from which the actual players will be chosen.
Is the standard django auth groups system the correct thing to use here or is there another way? I'd need it to be able to do invitations and stuff, obviously.
I can obviously write my own but is there another app out there that already does this kind of thing nicely?
If not, has anyone got any tips on how to go about this?
Creating your own model will give you more control to add extra information to those groups, such as the invitation system you described. The auth groups models was designed for classifying users by what level of control they have over the data on the website, which isn't what you want a groups model for. A new model will be much easier for you work with than trying to extend the existing groups model; which has built in functionality that you won't use, and probably has security features that will make it difficult to work with.

Restful API design with composite DTOs

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.

How would REST handle post-processing / including relevant resources?

I have a web service for a forum, and I have the following two resources:
/threads/frontpage, returns all the posts that belong on the front page of my site
/users/1, users/2, etc. returns users specified by the number.
And I want to make it so the user can ask for "all the threads on the frontpage, plus all the users that posted to those threads".
Normally I would separate it out into multiple requests, but that takes more time.
My only thought is to make a URL like this:
/threads/frontpage?includePostingUsers=true
In a way, it's taking the original result, and then using it to include additional info, in this case, the users that posted the threads.
But that doesn't seem very RESTful. There's a verb in there, and it just feels awkward. How would I do this RESTfully?
Thanks!
Having a verb in a query parameter is not necessary un-RESTful. I would say that it is common (and more important) to have clean resources and verbs, but to include more involved functionality into query parameters, as you would do with ?includePostingUsers=true.
Apigee published a nice pragmatic booklet on Crafting Restful APIs:
Web API Design – Crafting Interfaces that Developers Love (PDF), and a related video with real world observations: https://www.youtube.com/watch?v=QpAhXa12xvU#t=39m
If you don't want to show ?includePostingUsers=true in url then use Post request.
And why don't you just pass parameter like
/threads/frontpage?uid=1