api-design

Ignore or not API endpoint parameters based on access level


I am working on an API endpoint that returns a list of products:

"api/products"

The endpoint accepts the following parameters:

page_size
page_number 

Each product has a boolean property named IsApproved.

In the web application used by common users I always want to return only the Approved products ... On the web ADMIN application used by administrators I want to return all products, Approved or Not ...

My idea would be to add a new parameter (enumeration) named:

ApprovedStatus

And the values would be Approved, NotApproved and All.

On each API call I would check the user permissions ... If is admin I will consider the value on this parameter. If not then I will always return only approved products.

Another solution would be to have different endpoints ...

Any advice on which approach to take or is there other options?


Solution

  • The approval status is part of the product, therefore, in a perfect REST world, you don't want a different endpoint at all since you're accessing the same resource.

    Then, for filtering a resource based on a property value, I think the convention is that if you specify that property as a query parameter it will only return those matching the value, and if not, it will return all of them, so I don't see the need to define a special ApprovedStatus parameter with some special values. Just query by isApproved!

    Finally, about how to handle authorization. This, I think, should be handled at a completely separate layer**. If authorization is involved, you should have an explicit authorization layer that decides, for a specific resource and user, wether access is granted or not. This means the query would be triggered and if one of the resources generated by the query fails to be authorized for the user that triggered the query, it's taken out of the results. This accomplishes the behaviour you want without having any code that is checking specific users against specific query parameters, which is good because if tomorrow you have another endpoint that exposes this objects you won't have to implement the same authorization policy twice. Pundit is a perfect example on how to do this with Ruby elegantly.

    **Of course, this approach retrieves data from the database unnecessarily which could matter to you, and also opens your endpoint up to timing attacks. Even then, I would consider tackling these problems premature optimizations and should be ignored unless you have a very good reason.