Rest uri design for changing the status for resource
Asked Answered
C

6

27

I have a resource that can be reach at the URI /resources/{resource_identifier} and it has a 'status' property that I want be accessible. I've thought of a few options for this, which would be the 'best' or 'most RESTfull'?

Option One Append actions onto the URI and have the client POST to these URIs

/resources/{resource_identifier}/void    
/resources/{resource_identifier}/open    
/resources/{resource_identifier}/close

This looks clumsy though.


Option Two Use a query param in the URI and have the client PATCH to these

/resources/{resource_identifier}?transition=void
/resources/{resource_identifier}?transition=open
/resources/{resource_identifier}?transition=close

Option Three Use the payload of the request and have the client PUT

/resources/{resource_identifier}

payload options:

{ ..., "status" :"void" }
{ ..., "status" :"open" }
{ ..., "status" :"close" }

Or maybe something else altogether?

Catlett answered 14/8, 2013 at 13:51 Comment(0)
I
34

The first option is clearly not REST; you have 'actions' in the URI and are using POST, which is to create a new resource, which you clearly not attempting to do.

Looking at just the URI format for now. Option two is getting better, but query strings of that nature are more for reading data. Nothing really stops you doing it in this way. Option three has the best URI format, it is only referencing what resource you want to refer to in your request.

If we now consider the method of the request. In my book, this is rather simple, I presume that the status is only one field of this resource, and so if you are only doing a partial update, you are patching the resource, and thus PATCH is the method to use. On the off chance the 'status' is the only property, then changing the status is completely changing the resource and thus PUT would be acceptable; but I doubt that really is the case.

As it stands, the URIs of the third option, combined with use of PATCH is probably the best option.

PATCH /resources/{resource_identifier}

{ "status" :"close" }

Of course, you could also combine this with the concept of exposing specific attributes via their own URI as if they were a resource in their own right. Frankly, I don't like this, as it feels rather odd and only works for one attribute at a time. Still, if this is what you wanted to use, you could have something like:

PUT /resources/{resource_identifier}/status

close

Keep in mind, there is no "right" way of doing REST, just "not bad" ways. It's a style, not a rule set.

I also suggest you consider that being able to take many formats is a desirable feature, generally speaking. As such, the first option tends to be easier to work with. You could take JSON, as the example has, or swap it to XML <status>close</ status>, or a simple key value pair status=closed etc.

Invasion answered 20/7, 2015 at 14:30 Comment(14)
What about if you want to use hypermedia? Option one might be more suitable then right? So that these resources are only shown if applicable ( https://mcmap.net/q/505651/-hateoas-and-links-actions/… ). What do you think?Xeroderma
To be honest, I don't really understand what it is you are trying to ask. This question is about ReSTfull design, in which case, using an action as part of the URL is clearly against what was advised by Fielding, and if you are not basing you design on decisions on what Fielding advised in his paper, then you are not on about ReST and thus all is moot.Invasion
Why not, by makeing a list of different appropriate actions you are guiding the user to which changes of states are available (HATEOAS right?). Why is this not ReSTfull?Xeroderma
... it's not ReSTfull because you have the actions in the URL. It's a simple as that.Invasion
Keep in mind, there is no "right" way of doing REST, just "not bad" ways. It's a style, not a rule set.Mohair
@MosesSchwartz yes and no; there is an original description of how REST should be done, but yeah, really, just do what makes sense. You're going to have to document it anyway.Invasion
@Invasion I just quoted you, I thought it’s the greatest description of RESTMohair
Since the standard behaviors of PUT, GET, and DELETE map roughly to the CRUD paradigm, some believe that Resource APIs should only be used for CRUD use cases. This, however, is an incorrect assessment because POST can be used to execute behaviors that don’t map well to CRUD. Post is meant exactly for that. Make 3 post methods.Coriecorilla
@SiimNelis erm, GET and DELETE do cleanly map to Read and Delete. PUT has the confusion of being more of a complete Update (not partial, such as changing a field, unless you expose that field as it's own resource), but it can also be used to Create. POST is best used for Create. Using POST to trigger three actions is basically using POST for RPC and that's something REST is meant to be avoiding.Invasion
@Invasion you are right on the REST verbs part. What I'm saying REST gives you standard for CRUD operations but complex domains have behaviour which manipulates data on the server side, that doesn't come from the client but is a outcome of a computation. You have standard POST for you resource to create and you can have additional POST endpoints with a VERB that REST standard doesn't support.Coriecorilla
@SiimNelis I would be careful to not use 'standard' when it comes to REST, there is no standard, only conventions. Even the notion there is a set list of http verbs available is wrong. It's also not quite right to say that POST is the verb for creating a resource, PUT can also be used. If you wanted to, in theory, you can use any verb (even one you make), for a REST call, such as DISPATCH /order/123. Downside here is that ad-hoc verbs whilst technically valid are often treated as invalid and dropped. My example would be 'more REST' than doing something like POST /order/123/dispatch.Invasion
@Invasion post isnt idempotent and put is and you problably know this and what it means. Use the standard if there is one. But if there isnt why create a new http verb instead of a new uri for post. KISSCoriecorilla
The GitHub REST API offer us some examples that relate to this discussion. See how they handle locking an issue for example: they PUT .../issues/{issue_number}/lock and DELETE .../issues/{issue_number}/lock. It's interesting that this resembles real life putting on(PUT) an actually lock and removing(DELETE) from something.Derisive
I think both Siim and @Invasion have valid points, but the concern of adnan was still not properly addressed. If not having action names in URIs is RESTful, then HATEOAS and API discoverability through that is also RESTful. You can't have a REST API without HATEOAS. But changing entity's state through PATCH would mean that the client should know all possible statuses/states the entity can obtain. But having all the possible states as separate URIs available on the specific resource is a lot better in terms of API discoverability. So both approaches have one pro and one con in terms of REST.Practise
A
18

Why not have 'status' as resource. You can manage it. Also assume that there should be already a 'status' created as part of the {resource_identifier} resource creation and there is already a default value for the status.

Then the business logic need is just to 'update' the status via the rest call and therefore 'PUT' should be used.

updated Moving status to the Put-Body

PUT:    /resources/{resource_identifier}/status/

Body: {void | open | close }
Aharon answered 14/8, 2013 at 17:54 Comment(1)
I think PUTing to the /status/ resource makes sense. Although wouldn't you put the actual status: void, open, close in the body of the PUT rather than as part of the URI?Liebig
E
6

There are many cases that state changes have a lot of business logic. While the answers are based on the "Rest standards", I think there are cases that are not simply changing a state field.

For example, if a system has to cancel an order. This is not simply to change a state, since the order has many states and each change represents a lot of logic (notifications, verifications, etc.)

In the cases of using:

PATCH /order/1
{ "status" :"cancelled" }

I can assure you that the logic will be scattered by the client and the server, it will be difficult to maintain, and it will not have an elegant code (especially on the server side, which will verify the previous, subsequent state, if the change is consistent, and it will be mixed with the update responsibility).

I see it simpler to have a cancel method and do its job. I think in many cases it is more elegant to do:

PATCH: /order/1/cancel 

//you could use the body with some cancellation data.

The following link can help you: https://phauer.com/2015/restful-api-design-best-practices/#keep-business-logic-on-the-server-side

Emblements answered 8/8, 2019 at 22:22 Comment(0)
O
1

Your second option looks better because you're maintaining the RESTful url structure and not appending RPC-style methods to the end of it.

Why not just do this:

PUT to /resources/:id and send the data transition=void with the request.

It behaves in the same way it would if you were receiving a POST request, just grab the data out of the request body.

Octangle answered 14/8, 2013 at 15:10 Comment(1)
Thanks... But we are doing resource creation and actions in POST request.... For update only we use PUT request... Once again Thanks..Catlett
C
0

Since the standard behaviors of PUT, GET, and DELETE map roughly to the CRUD paradigm, some believe that Resource APIs should only be used for CRUD use cases. This, however, is an incorrect assessment because POST can be used to execute behaviors that don’t map well to CRUD.

Coriecorilla answered 2/7, 2020 at 10:46 Comment(0)
B
0

In my own opinion, I use both structure generally agreed here. However, the following is how I draw the line.

In situations where the update to an attribute to a resource has side effects (like send a mail if the value of the attribute is XYZ), I make it have its own resource (i.e. endpoint. eg. PUT /resources/:id/status) this will simplify things at the controller level. Otherwise, I'd use the resource of its parent (PATCH /resources/:id/status)

Bankroll answered 9/8, 2021 at 13:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.