I read quite some stuff about RESTful API Design.
But when it comes to the implementation, it wasn't that easy anymore.
I got stuck at the following problem:
Assume the following 2 endpoint:
/api/v1/users/:id
/api/v1/users/1/friends/:id
As we all can see, friends is a collection of the resource user.
A user can have n-friends in his friendslist (by standard this would be many to many, but for now, let's assume this to be one to many).
Okay, now i want to REMOVE a user (id=3) from the friendslist of user 1 by doing the following HTTP-Request:
DELETE api/v1/users/1/friends/3
And this is where i got stuck - either the request deletes the whole user resource which has id = 3 or removes the resource from the collection. Because both would be valid Restful implementations i think.
So the question is:
How to remove an item from the collection without deleting the original resource
I hope that this question is no duplicate - but i did google a lot to find the answer. Maybe i don't know the related technical term to find some pleasing results...
Thanks in forward.
The approach to REST looks fine but that really only speaks to path format and HTTP verb. The problem must be in your application code or app routes.
I think it is better that DELETE api/v1/users/1/friends/3 would be used to delete user 3, just like DELETE api/v1/users/1 would be used to delete user 1.
To remove just user 3 from being a friend of user 1 I would use DELETE api/v1/users/1/friends and specify a filter to only remove friends with the id of 3.
DELETE api/v1/users/1/friends without a filter would remove all friends of user 1.
Likewise to add friends of user 1 I would use PUT api/v1/users/1/friends and specify the ids of the friends to add.
Related
I am designing an application that will expose a REST API.
URLs for the resources themselves will look fairly standard, like below:
GET /orders //Get all orders
GET /orders?somefilter=somecriteria //search for orders
GET /orders/<orderid> //specific order
PUT /orders/<orderid> //update a specific order
POST /orders //create an order
My question is regarding resources related to these. I expect the resources will mainly be accessed through an app, but still would like want to provide basic web entry forms, as well as schemas for various resources. What url should they have?
Possible urls
//Option1
GET /forms/orders //new order
GET /forms/orders/<orderid> //edit existing order
GET /schemas/orders
//Option2
GET /orders/form //new order
GET /orders/<orderid>/form //edit existing order
GET /orders/schema
//Option3
GET /orderform //new order
GET /orderform/<orderid> //edit existing order
GET /orderschema
Option 2 doesn't seem right to me, I don't think that the form resource should share the same location on a URL as the order ID. Option 1 looks the best, but would increase the organisational complexity of the app as I couldn't keep the schemas with the rest of the code dealing with a particular resource (but that is a problem that can be solved).
Is there any accepted best practice for these? It does not have to be one of the three options above, any and all pointers would be appreciated.
At the moment I am adding the user to one group at a time using this endpoint:
PUT /{realm}/users/{id}/groups/{groupId}
In my use case it would be beneficial to perform the affectations in bulk, so far I haven't found a documented way of doing so, is there a way to do it?
Thanks
PUT /{realm}/users/{id}
It's in the documentation, but it doesn't work.
I started discussion on github
You could try to update the full user data
PUT /{realm}/users/{id}
with a partial UserRepresentation containing a minimal json with "groups" array only ?
I see that nearly all fields are marked as optional:
cfr https://www.keycloak.org/docs-api/12.0/rest-api/index.html#_userrepresentation
I read that the route for getting a nested resource in REST should look like this
/articles/:articleId/comments
The owner (:articleId) of the child resource will be visible.
But what if you have an owner that you don't want the client to know about?
For example, let's say I have an app where users have anonymous posts. I wouldn't want other users to see the client fetching the post by /users/123/post/321 because users could identify who wrote the post from the id and it wouldn't be anonymous.
Is the id necessary? Is it ok to instead do /users/posts/321 if all posts have a unique id?
There are no actual requirements for the URL format. It can be whatever you'd like it to be.
If it were me, I would use simply /posts/321 and leave users out of it, since a particular user isn't specified in your URL at all. I think that's the clearest way to handle it in your case.
How many sub-collections can have a resource?
Just imagine that we have this model:
accounts -> posts -> comments
Everything is clear for accounts-posts pair.
/accounts/{account_id}/posts/{post_id}
But what about comments? What is a proper way to point to a single comment?
/posts/{post_id}/comments/{comment_id}
or
/accounts/{account_id}/posts/{post_id}/comments/{comment_id}
or (direct pointing)
comments/{comment_id}
The general rule of thumb is to only go one layer of subresources deep. An account may have many posts like you show, and a post may have many comments, but since the post id is unique, including the account id is a bit redundant when trying to get the comments for a post.
/accounts/:account_id/posts
/posts/:post_id/comments
Ruby On Rails also lists this in their docs (just for a bit of a citation). https://guides.rubyonrails.org/routing.html#limits-to-nesting
Additionally, if you already have the id of a resource you don’t need to nest it. As short of a route that gets the job done is preferred.
/comments/:id
I need to design an operation “duplicate” for "articles".
My thought was: a POST on apibaseurl/articles/{id}/duplicates and returning a 200 OK with the URI of the created duplicate, which's URI however will conform to the template apibaseurl/articles/{id}.
When issuing a GET to apibaseurl/articles/{id}/duplicates however, there will not necessarily be a list of duplicates (meaning: the server will not keep track of all duplicates created for an article - the "duplicate" relationship is ignored by the server outside the scope of the request)
Questions:
is my suggested solution OK?
does it not violate any RESTful principle by having the URI of the created object point to a location not under the resource under which it was posted?
would I have to provide a client with the possibility to list all duplicates for an article?
is my suggested solution OK?
It looks fine to me.
does it not violate any RESTful principle by having the URI of the created object point to a location not under the resource under which it was posted?
No, that is not necessary. You POST to a collection resource but this does not force you to return a Location header pointing inside this collection.
would I have to provide a client with the possibility to list all duplicates for an article?
If you have a use case for this, you could provide it. But if there is no business interest in listing the articles created as duplicates of an existing article, you don't have to.
Go ahead :)