restapi-designrestful-architecture

REST GET endpoints returning different models based on user role


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


Solution

  • 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.