REST Api design for updating a single attribute of a resource - rest

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.

Related

RESTful API, query params on PUT

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.

REST: How to support create-Or-Update and partial-update ? (aka PUT vs PATCH)

We are designing WebAPI for our software for managing ecommerce product information. We want to provide (among many others) two operations:
Simple one: allow user to add/modify existing product information:
don't create new product if it not exists
don't delete any information from existing product which was not provided in this request
In my opinion HTTP PATCH method is proper way to handle this scenario (with json-patch or json-merge-ptach) with URL like this: /products/{ID}
Harder one: allow user to add/modify existing product or create one
create product if not exists in DB
don't delete any information from existing product which was not provided in this request (same behaviour as in first case)
I'm struggling with designing REST endpoint for this second use case. I have few options but none of them fits perfectly for me in the REST principles:
a) Add custom HTTP header to the endpoint designed for first case (patch) to allow a caller to control of "not found behaviour" eg. create-entity-when-not-exists: true/false - but in my opinion PATCH shouldn't be used for creating resources.
b) Design new endpoint using PUT with special header "preserve-not-provided-data" - this on the other hand violates for me PUT principles because PUT is create-or-replace not create-or-update method
c) Create PATCH for /products URL (without {ID} at the end) - in this case we are updating whole collection(resource) of products - so if product exists we can update it or create new one if not exists.
For now c) solution looks fine for me with one exception: If in the future we would like to support batch operations (for both use cases: 1 and 2) we would like to use /products URL and it will conflict with URL from solution c)
What do you think ? Do you have any other ideas ?
PUT and PATCH have differing message semantics, but the core context ("remote authoring") is the same. In both cases, the client request is "Please, server, make your representation of this resource match my local copy".
For example, I GET a JSON document from the server. I make local edits to it. Now I want to "save" my changes on the server. If the document is modest in size, I might just send the entire revised document over the network. If the document is very large, and my changes are modest, then I might instead send the patch instead.
If you imagine using HTTP to publish edits of HTML web pages to a server, then you've got the right frame of reference. There's not a lot of practical difference between "please patch the title of your copy of the document" and "here is a complete new copy of the document, with my edit to the title". The bytes on disk are going to be the same in either case.
Given that, it would be very odd if those two methods for publishing a new revision of the document were to have vastly different side effects.
Your third approach, based on modifying /products, is potentially fine for both your individual and batch. The server gets the new representation of /products (or the patch document describing the changes), decides whether to accept the changes, and if so computes what it needs to do to its own database to make things work.
Note:
A PUT request applied to the target resource can have side effects on other resources.
The HTTP specification is relatively strict about what the message means, but offers the server a lot of leeway in how it behaves in response.

REST url proper format

my REST API format:
http://example.com/api/v1.0/products - get all products
http://example.com/api/v1.0/products/3 - get product with id=3
Also, the products can be orginized into a product groups.
What is a proper way to get all product groups according to REST best practices:
http://example.com/api/v1.0/products/groups
or
http://example.com/api/v1.0/productgroups
...
another option ?
I can't agree with Rishabh Soni because http://example.com/api/v1.0/products/groups may lead to ambiguity.
I would put my money on http://example.com/api/v1.0/productgroups or even better http://example.com/api/v1.0/product_groups (better readability).
I've had similar discussion here: Updating RESTful resources against aggregate roots only
Question: About the thing of /products/features or /product-features,
is there any consensus on this? Do you know any good source to ensure
that it's not just a matter of taste?
Answer: I think this is misleading. I would expect to get all features
in all products rather than get all possible features. But, to be
honest, it’s hard to find any source talking directly about this
problem, but there is a bunch of articles where people don’t try to
create nested resources like /products/features, but do this
separately.
So, we can't be sure http://example.com/api/v1.0/products/groups will return all possible groups or just all groups that are connected with all existing products (what about a group that has not been connected with the product yet?).
To avoid this ambiguity, you can add some annotation in documentation. But you can just prepare http://example.com/api/v1.0/product_groups and all is clear.
If you are developing Rest API for your clients than you should not rely on id's. Instead build a meaningful abbreviation and map them to actual id on server side.
If that is not possible, instead of using
http://example.com/api/v1.0/products/3 you can use http://example.com/api/v1.0/products?product_id=3 and then you can provide "product_id" description in the documentation. basically telling the client ways to use product_id.
In short a url must be meaningful and follow a pattern.The variable part must be send by in the url query(part after ? or POST payload)
With this, method to querying the server is also important. If client is trying to get something to the server he should use "GET" http request, similar POST http request if it is uploading new info and "PUT" request if it is updating or creating a new resource.
So by this analogy http://example.com/api/v1.0/products/groups is more appropriate as it is following a pattern(groups in product) while productgroups is more like a keyword with no pattern.
A directory like pattern is more easier to understand. Like in file systems(C:\Program Files\WinRAR), every part gets us to more generalized target.
You can also customize this for specific group- http://example.com/api/v1.0/products/groups?id=3

REST API with segmented/path ID

I am trying to design a REST API for a system where the resources are essentially identified by path-like addresses with varying numbers of segments. For example, a "Schema" resource could be represented on the file system as follows:
/Resources/Schemas/MyFolder2/MyFolder5/MySchema27
The file-system path /Resources/Schemas/ is the root folder for all Schemas, and everything below this is entirely user defined (as far as folder depth and folder naming). So, in the example above, the particular Schema would be uniquely identified by the following address (since "MySchema27" by itself would not necessarily be unique):
/MyFolder2/MyFolder5/MySchema27
What would be the best way to refer to a resource like this in a REST API?
If I have a /schemas collection my REST URL could be:
/schemas/MyFolder2/MyFolder5/MySchema27
Would that be a reasonable approach? Are there better ways of handling this?
I could, potentially, do a 2-step approach where the client would first have to search for a Schema using the Schema address (in URL parameters or in the request body), which would then return a unique ID that could then be used with a more traditional /schemas/{id} design. Not sure that I like that, though, especially since it would mean tracking a separate ID for each resource. Thoughts? Thanks.
The usual way to add a resource to your "folder" /Resources/Schemas/ is to make a POST request on it with the body of this POST request containing a representation of the resource to add, then the server will take care of finding the next free {id} and and setting the new resource to /Resources/Schemas/{id}.
Another approach is to, as you said, make a GET request on /Resources/Schemas/new which would return the next free {id}, and then, make a second request PUT directly on /Resources/Schemas/{id}. However this second approach is not as secure as the first since two simultaneous request could lead to the same new {id} returned and so the second PUT would erase the first. You can secure this with some sort of reservation mechanism.
This is called as Resource Based URI approach for building REST services . Follow these wonderful set of video tutorials to understand more about them and learn how to implement too . https://javabrains.io/courses/javaee_jaxrs

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.