I am aware of this question especially this answer.
According to the documentation calling GET /{realm}/users gets you a UserRepresentation, which lists clientRoles as optional. That suggests, that it should be available in principle. But I do not know how I can leverage this.
I defined the endpoint as
const usersEndpoint = `${adminEndpoint}/realms/${realm}/users`;
Which should be correct.
Or am I reading something wrong?
I was thinking about it the wrong way. You are able to get a list of users having a role or a group by:
GET /{realm}/clients/{id}/roles/{role-name}/users
resp.
GET /{realm}/groups/{id}/members.
In order to get the list of every user having which roles, you could iterate over all roles and request their repective users and merge it.
Or in my way, retrieving the list of users having a discrete role was enough to achieve what I wanted.
Related
I´m using the official Keycloak API. I have a list of ids and would like to get all users represented by the ids. So let´s say i have a list with ids 1, 7, 9. Optimally i would would want to have a GET endpoint which accepts a list/array of ids as a PathVariable. But it seems like there´s no method like this. So i think i either have to send a seperate request for each id in the list and get the according user(which would result in n requests with a list of size n) or i have to get all users and filter them afterwards. Is there no better way?
You can create your own Keycloak extension like this one: https://github.com/cloudtrust/keycloak-rest-api-extensions.
Or as it is pointed out by #cyee in this question, some OAUTH providers recommend having a separate database with users' info. Of course, that requires creating a separate "auth-api" which would behave as middleware (updating a user would trigger an update of database).
I'm rewriting an API to be more RESTful, but I'm struggling with a design issue. I'll explain the situation first and then my question.
SITUATION:
I have two sets resources users and items. Each user has a list of item, so the resource path would like something like this:
api/v1/users/{userId}/items
Also each user has an isPrimary property, but only one user can be primary at a time. This means that if I want to get the primary user you'd do something like this:
api/v1/users?isPrimary=true
This should return a single "primary" user.
I have client of my API that wants to get the items of the primary user, but can't make two API calls (one to get the primary user and the second to get the items of the user, using the userId). Instead the client would like to make a single API call.
QUESTION:
How should I got about designing an API that fetches the items of a single user in only one API call when all the client has is the isPrimary query parameter for the user?
MY THOUGHTS:
I think I have a some options:
Option 1) api/v1/users?isPrimary=true will return the list of items along with the user data.
I don't like this one, because I have other API clients that call api/v1/users or api/v1/users?isPrimary=true to only get and parse through user data NOT item data. A user can have thousands of items, so returning those items every time would be taxing on both the client and the service.
Option 2) api/v1/users/items?isPrimary=true
I also don't like this because it's ugly and not really RESTful since there is not {userId} in the path and isPrimary isn't a property of items.
Option 3) api/v1/users?isPrimary=true&isShowingItems=true
This is like the first one, but I use another query parameter to flag whether or not to show the items belonging to the user in the response. The problem is that the query parameter is misleading because there is no isShowingItems property associated with a user.
Any help that you all could provide will be greatly appreciated. Thanks in advance.
There's no real standard solution for this, and all of your solutions are in my mind valid. So my answer will be a bit subjective.
Have you looked at HAL for your API format? HAL has a standard way to embed data from one resources into another (using _embedded) and it sounds like a pretty valid use-case for this.
The server can decide whether to embed the items based on a number of criteria, but one cheap solution might be to just add a query parameter like ?embed=items
Even if you don't use HAL, conceptually you could still copy this behavior similarly. Or maybe you only use _embedded. At least it's re-using an existing idea over building something new.
Aside from that practical solution, there is nothing in un-RESTful about exposing data at multiple endpoints. So if you created a resource like:
/v1/primary-user-with-items
Then this might be ugly and inconsistent with the rest of your API, but not inherently
'not RESTful' (sorry for the double negative).
You could include a List<User.Fieldset> parameter called fieldsets, and then include things if they are specified in fieldsets. This has the benefit that you can reuse the pattern by adding fieldsets onto any object in your API that has fields you might wish to include.
api/v1/users?isPrimary=true&fieldsets=items
We are building a REST API with the following resources: Users, UserGroups. Currently we are supporting the following URI's:
/BASEAPI/VERSION/Users/
/BASEAPI/VERSION/Users/{id}/UserGroups
/BASEAPI/VERSION/UserGroups/
/BASEAPI/VERSION/UserGroups/{id}/Users
I like this better than including references in the objects which then have to be pulled on subsequent requests. It also means that we can avoid query params to filter the results. i.e. we don't have to support:
/BASEAPI/VERSION/UserGroups/{id}?user_id={user_id}
The problem is that it doesn't make creation and deletion semantics very clear. i.e. should a DELETE request to:
/BASEAPI/VERSION/Users/{id}/UserGroups/{group_id}
remove the UserGroup, or remove the user from the user group?
We've considered adding:
/BASEAPI/VERSION/UserGroupUsers
But something doesn't quite feel right about that, but maybe it's the best way to go. What do others think are best practices?
You need to figure out how you intend to represent the membership relationship between user and user group. It can be an attribute of the user, an attribute of the group, or a separate resource. Those are the only choices. How users are added to and removed from groups falls out naturally from your choice. Membership management becomes a PUT/DELETE to the user, the group, or the membership resource.
Personally, I find the separate resource to be the cleanest way to handle the issue, but you then need query parameters to poll for a specific user or group. Also, you'd need to change your second-level resource names, because it makes no sense for /userGroups/{id}/users to return a collection of userGroupUsers resources.
A URL addresses a resource. A GET on this URL returns the resource and a DELETE deletes it. If the DELETE would delete something different than the GET is returning something really is broken.
So if /BASEAPI/VERSION/Users/4711/UserGroups would return the UserGroups with the ID 0815 and 0816 the DELETE should delete both userGroups.
Question is: Does this make sense? What is happening to the other users in both userGroups?
If you want to remove a user from a group I would provide a PATCH Method.
Say there are users having multiple authorizations having multiple permissions.
Retrieving all authorizations for the specified user (without permissions) could be:
GET users/{id}/authorizations
The "normal" case is to not embed permissions with authorizations for performance reason.
There are cases when authorizations must be returned with their respective permissions for that user.
Suggested solutions are:
GET users/{id}/authorizations/permissions // does not seem clear
GET users/{id}/authorizations?permissions=true // with query string
GET users/{id}/authorizationswithpermissions // new resource
Now what is the best way to design the REST URI in that case?
Your ideas
There are cases when authorizations must be returned with their respective permissions for that user.
GET users/{id}/authorizations/permissions
It is not a good idea to nest collection resource like this. Does it mean "give me all permissions of all authorizations of user id"? This is unclear. Don't do this.
GET users/{id}/authorizations?permissions=true
A query is normally used to query, search, or filter on a collection resource. This URL woud return all authorizations for user id for which permissions is true. But what does that man? This is unclear. Don't do this.
GET users/{id}/authorizationswithpermissions
Authorizations are authorizations. Their representation should not depend on the URI. Don't do this.
Content Negotiation
The solution to your problem is to use content negotiation. You only use one URL:
GET users/{id}/authorizations
This means: Give me a list of all authorizations of user id.
Now if you want to get this list without permissions, you could use the HTTP header
Accepts: application/vnd.mycompany.authorizations+xml
Let's digest this.
application: the first part of the normal MIME type application/xml
vnd: a prefix to define your own type
mycompany.authorizations: your type
xml: the second part of application/xml
Now if you want to get this list with permissions, you could use the HTTP header
Accepts: application/vnd.mycompany.authorizations.permissions+xml
Note that me now use vnd.mycompany.authorizations.permissions. The server should return the authorizatons including the permissions. Only the representations are different, not the resources.
Personnally I can't find any problem with both two last suggestions:
GET users/{id}/authorizations?permissions=true // with query string
GET users/{id}/authorizationswithpermissions // new resource
Except I would change them as follow to be more relevant:
GET users/{id}/authorizations?withPermissions=true // with query string
GET users/{id}/authorizationsANDpermissions // new resource
The first one seems to be quite confusing but your RESTful entities should be documented whatever notation you will opt for.
I want to expose my Item resource in these ways:
GET /Item (to show all Items)
GET /Item/401 (to show only the Item with key value 401)
So far so good. Now to request only the Items that belong to Me, I can think of these possible URIs constructions:
GET /Item/Mine
GET /MyItem
GET /Item/owner=42 (where my ID is 42)
I don't like the last one because it simplifies my client programming to rely on existing authentication to figure out "My" ID. I happen to be coding on ASP.NET WebAPI, but I'm really asking about the principle and design, not the implementation.
My question: Which of the three ways to represent "My" Items is most consistent with the RESTful design concept? Is it even legitimate to ask for "My" Items as such?
If users should not be able to see items that aren't "theirs", then this is an authorization issue. Just use GET /Item, and have your authorization module strip out the items that aren't theirs.
If users can see all items, and you just want to grab the items that belong to a particular user, then you should be parameterizing the call to GET /Item. Something like GET /Item/?owner=42. In this case, the user isn't limited to asking for their items .. they can ask for the items of any owner. That buys them flexibility without costing you anything.
If you have a /User resource, you could also add an endpoint /User/{id}/Item, which
returns the same collection as /Item/?owner=
And this isn't germane, but I find that plural collections (/Items, /Users) read a lot better than singulars. YMMV.
I would use GET /Items to get all itmes.
And GET /Items?owner=42.
GET /Item/Mine is not consistent since it contradicts your way of identifying the resource ie, GET /Item/401.
GET /MyItem seems seems unnecessary since the resources you are looking for can be retrieved using the other REST url paths.