I'm currently dealing few endpoints returning different kinds of models based on permissions:
For example, our business object is getting converted to either an object of type Model
or AdvancedModel
.
public class Model
{
public int Property1 {get; set;}
}
public class AdvancedModel : Model
{
public int Property2 {get; set;}
}
public IActionResult Get()
{
(...)
return User.IsAdmin
? Mapper.Map<AdvancedModel>(Client);
: Mapper.Map<Model>(Client);
}
Initially this was built so everyone could retrieve client's basic details (name...) BUT only admin could get access to "sensitive" information (preferred payment info, billing contacts).
This makes makes our API harder to understand as we need to identity what fields are returned based on the permission level... This works well but I'm afraid it will become funky as we scale up (new roles, endpoints).
We have considered introducing new endpoints but it will add a bunch of them to our already packed API.
/api/v1/admin/clients/1234
vs
/api/v1/clients/1234
I was just wondering what's the best practice to handle that kind of scenario?
Thx
I've found that it can become confusing for a REST api to return different things depending on who's accessing the resource. This becomes even more complicated when you're accepting changes with PUT
.
I don't think this a general advice, because different situations might require different solutions, but in your specific case I think it makes more sense to just have different resources.
It's fine for a 'piece of data' to be represented on more than 1 point in the API, however, another thing you could do is consider the following:
/clients/1234 <- could contain all the data
everyone may see.
/clients/1234/billing <- contains only the
billing information
admins can see.
I think this also plays well into the idea that it's good to avoid inheritance and use composition instead. You don't need a Model
and an AdvancedModel
. You need both Model
and a Billing
model.
In addition to what was posted by Evert, you could use different media types
for different responses. The media-type is also a good place to support versions in your api.
//fullrecord is only returned to admins
GET -H"accept=application/vnd.yourcompany.fullrecord.v1+json" /clients/1234
//fullrecord can also only be set by users with admin role
PUT -H"content-type=application/vnd.yourcompany.fullrecord.v1+json" /clients/1234
For all others
//this will just return public info
GET -H"accept=application/vnd.yourcompany.v1+json" /clients/1234
For the client
//this will just return infos for logged in the client
GET -H"accept=application/vnd.yourcompany.client.v1+json" /clients/1234
This would mean that a user with role admin can explicitly request a certain view by setting the appropriate accept header. It also leads to a cleaner URI design.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With