RESTful API, query params on PUT - rest

I am struggling with developing an API that follows RESTful best practices for my use case.
My db model looks something like:
Company:
Id
Name
Location:
Id
Name
DefaultSetting
LocationSettings:
Id
LocationId
CompanyId
Setting
In the business model, not every company has set location values, so in many cases it will default to the value from Location. If the user decides to change the value, then we will store their custom settings instead of using the default.
I was thinking of an API along the lines of:
GET /location-settings?companyId=id
GET /location-settings?companyId=id&locationId=id
PUT /location-settings?companyId=id&locationId=id
The idea is that when a user decides to change any setting, we will invoke the PUT route - it will update the location settings if custom settings exist for this company, or create a new entry in LocationSettings if it does not exist.
However, this seems like it might be an anti-pattern as normally I do not see query parameters used in such a manner on PUT routes to specify which resource to update. In this case, I cannot easily provide an ID for the location-settings resource because it may or may not exist. I did not want to use 2 separate routes (one for PUT and one for POST) because in the application's use-case this would get confusing i.e. from an end-user's perspective the default settings logic is hidden, so they always have location settings for their company and are simply updating them.
Another option I was thinking of was (OPTION 2):
GET /location-settings?companyId=id
GET /location-settings/locations/{locationId}?companyId=id
PUT /location-settings/locations/{locationId}?companyId=id
However, this seems strange because locations is not a sub-resource of location-settings.
A 3rd option I was considering was (OPTION 3):
GET /locations/location-settings?companyId=id
GET /locations/{locationId}/location-settings?companyId=id
PUT /locations/{locationId}/location-settings?companyId=id
Personally I liked this option the best. However, I am not sure that referencing 2 collections like the first get route does without an ID is a good REST practice.
Any recommendations on this?

It sounds like every company only has 1 'location-settings'.
If that that's true, you don't really need to add the location settings id to the url.
I might be wrong, but it seems like the only 2 routes you need are:
GET /company/{id}/location/{locId} - Return custom location settings OR default
PUT /company/{id}/location/{locId} - Update custom location for location

I do not see query parameters used in such a manner on PUT routes to specify which resource to update.
That's true, you don't. But there is nothing wrong with doing it that way
PUT /x/y/z
PUT /x?y=z
Both of those URI are fine; general purpose components will do the right thing, URI templates describe them easily, and so on. There are tradeoffs between them, of course (convenience for html vs convenience of relative references); but you could easily have one of them re-direct to the other if you discovered later that you wanted to change things.

Related

How to properly access children by filtering parents in a single REST API call

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

REST where should end point go?

Suppose there's USERS and ORDERS
for a specific user's order list
You could do
/user/3/order_list
/order/?user=3
Which one is prefered and why?
Optional parameters tend to be easier to put in the query string.
If you want to return a 404 error when the parameter value does not correspond to an existing resource then I would tend towards a path segment parameter. e.g. /customer/232 where 232 is not a valid customer id.
If however you want to return an empty list then when the parameter is not found then query string parameters. e.g. /contacts?name=dave
If a parameter affects an entire URI structure then use a path e.g. a language parameter /en/document/foo.txt versus /document/foo.txt?language=en
If unique identifiers to be in a path rather than a query parameter.
Path is friendly for search engine/browser history/ Navigation.
When I started to create an API, I was thinking about the same question.
Video from apigee. help me a lot.
In a nutshell when you decide to build an API, you should decide which entity is independent and which is only related to someone.
For example, if you have a specific endpoint for orders with create/update/delete operations, then it will be fine to use a second approach /order/?user=3.
In the other way, if orders have only one representation, depends on a user and they don't have any special interaction then you could first approach.
There is also nice article about best practice
The whole point of REST is resources. You should try and map them as closely as possible to the actual requests you're going to get. I'd definitely not call it order_list because that looks like an action (you're "listing" the orders, while GET should be enough to tell you that you're getting something)
So, first of all I think you should have /users instead of /user, Then consider it as a tree structure:
A seller (for lack of a better name) can have multiple users
A user can have multiple orders
An order can have multiple items
So, I'd go for something like:
The seller can see its users with yourdomain.com/my/users
The details of a single user can be seen with yourdomain.com/my/users/3
The orders of a single user can be seen with yourdomain.com/my/users/3/orders
The items of a single order can be seen with yourdomain.com/my/users/3/orders/5

REST Api design for updating a single attribute of a resource

As from the specification of the project I am working, it is required to expose an API that allows to change the status of a user entity to be one of [ VALID | NOT_VALID | TO_VALIDATE ].
Current API for users have this path
/user/:user_id
my idea was to add a new sub-path for POST with url:
/user/:user_id/status
Since I want to update just a single value which design choice you would find to be the best?
Using the request's body (JSON)
Using the query string e.g. /user/:user_id/status?value=VALID
Creating three endpoints, one for each possible status' value:
/user/:user_id/status/valid
/user/:user_id/status/not_valid
/user/:user_id/status/to_validate
Thanks.
If status is something that is not query-able, then you could even have it as part of the user entity itself like /user/:user_id and do a PATCH (with the JSON payload) to update the status. Generally, people prefer nested paths if the sub-path can be queried as sub-resource on its own or updated independently. So if someone needs the status of a user, would he not expect that to come in the GET result of /user/:user_id? Or is he required to make another GET call to /user/:user_id/status? I think the /status path might not be a great idea.
Also, if you add something like status now, what will happen if you need to update name, address etc. in the future. We don't want to keep adding new sub-paths for every field right? Also having an enum-like sub-path in the URL path (valid/not_valid etc.) doesn't seem to be the right thing to do. If you include it in the JSON payload, it would come under the schema and you could version it nicely in case you make new additions to the enum. Having it as part of the URL means the clients now have to know about the new path as well.
On the other hand, you should also think about usability of the API. One rule of thumb I generally follow in designing REST APIs: I want my clients to integrate with my API in 2 minutes or so and I have to minimise the number of things he needs to know in order to successfully integrate. All standards and norms might come secondary to usability.

REST url for unique resource (url with singular ?)

I have a webserver with some configuration properties and I want to be able to change them using a REST API.
Example
{
"maxUsers" : 10,
"refreshPeriodInMin" : 5
}
I would like to represent this with a "configuration" object. According to REST principle I believe the best way to do it is :
GET/PUT/POST/DELETE /configurations/{id}
But in my case I have only one configuration object and I do not like the idea of have to query
GET /configurations
just for one object.
Because there is only one object the easiest solution I found is to use id=default
Would give something like
GET /configurations/default
Is there a better way to represent a "unique" resource ? As mentionned by djmorton in the comments would /configuration be correct in a REST world ?
Another solution I though about would be to have one object per property. This would give
GET /properties/maxUsers
Problem with that solution is that you need to know the name of property to be able to query it. PLus you will make several queries if you have multiple changes to make.
Keep the resource singular if it truly represents a singular thing. If you will only have one, there is no reason not to simply PUT to that resource when you want to create or update it, and GET from that resource when you want to retrieve it.
If it can not be deleted, return a 405 METHOD NOT ALLOWED on DELETE requests. If it can be deleted, a DELETE request to that resource is acceptable, after which GET requests can return a 404 NOT FOUND.
In many ways, adding an id element to the path like /configuration/default would probably confuse users because they might expect that they would be able to POST new configurations to /configuration in addition to the default one.
The key is to do something that is sensible and intuitive to consumers of the API.

RESTful url to GET resource by different fields

Simple question I'm having trouble finding an answer to..
If I have a REST web service, and my design is not using url parameters, how can I specify two different keys to return the same resource by?
Example
I want (and have already implemented)
/Person/{ID}
which returns a person as expected.
Now I also want
/Person/{Name}
which returns a person by name.
Is this the correct RESTful format? Or is it something like:
/Person/Name/{Name}
You should only use one URI to refer to a single resource. Having multiple URIs will only cause confusion. In your example, confusion would arise due to two people having the same name. Which person resource are they referring to then?
That said, you can have multiple URIs refer to a single resource, but for anything other than the "true" URI you should simply redirect the client to the right place using a status code of 301 - Moved Permanently.
Personally, I would never implement a multi-ID scheme or redirection to support it. Pick a single identification scheme and stick with it. The users of your API will thank you.
What you really need to build is a query API, so focus on how you would implement something like a /personFinder resource which could take a name as a parameter and return potentially multiple matching /person/{ID} URIs in the response.
I guess technically you could have both URI's point to the same resource (perhaps with one of them as the canonical resource) but I think you wouldn't want to do this from an implementation perspective. What if there is an overlap between IDs and names?
It sure does seem like a good place to use query parameters, but if you insist on not doing so, perhaps you could do
person/{ID}
and
personByName/{Name}
I generally agree with this answer that for clarity and consistency it'd be best to avoid multiple ids pointing to the same entity.
Sometimes however, such a situation arises naturally. An example I work with is Polish companies, which can be identified by their tax id ('NIP' number) or by their national business registry id ('KRS' number).
In such case, I think one should first add the secondary id as a criterion to the search endpoint. Thus users will be able to "translate" between secondary id and primary id.
However, if users still keep insisting on being able to retrieve an entity directly by the secondary id (as we experienced), one other possibility is to provide a "secret" URL, not described in the documentation, performing such an operation. This can be given to users who made the effort to ask for it, and the potential ambiguity and confusion is then on them, if they decide to use it, not on everyone reading the documentation.
In terms of ambiguity and confusion for the API maintainer, I think this can be kept reasonably minimal with a helper function to immediately detect and translate the secondary id to primary id at the beginning of each relevant API endpoint.
It obviously matters much less than normal what scheme is chosen for the secret URL.