Using HTTP DELETE method to cancel an action in progress - api

Background:
I provide a programming interface for people who wish to place orders using my site.
They can use GET and POST methods on /api/v1/orders to place an order and to view list of all orders placed by them. They can also use the GET metod on /api/v1/orders/<order_id> in order to view specific details of one order.
There is a need to provide a way to cancel an order, however the records themselves need to be kept.
I would like to get feedback from more seasoned developers on whether it would be a sane decision to:
a) implement the DELETE verb on /api/v1/current_orders/<order_id>, which would delete it from the list of "current" orders (by marking it as cancelled). The downside is that it will make use of a different noun, which may be confusing.
b) implement the DELETE verb on /api/v1/orders/<order_id> with the same functionality as in a). This is somewhat misleading, as the entity will not really be deleted, and the consumer should be aware of that.
c) implement the POST verb on /api/v1/cancellations/<order_id> (or POST on /api/v1/cancellations with the order_id in the JSON payload). This seems to be less than ideal because a resource will not be created as a result of that request. However, the consequences of using this endpoint seem to be clearer.
d) ...?
Question:
I am aware that there is not always a "perfect" solution to designing endpoints for a REST API, but keeping in mind the need for clarity and intuitiveness and with a high regard for best practices, which of the options is "optimal"?

What about PATCH verb on /api/v1/orders/<order_id> indicating that it is cancelled?
HTTP PATCH : Allows to do partial modifications in an entity. While POST creates a new one, and PUT replaces an existing one, PATCH just updates the properties you are sending, leaves the rest at they are.
You would need only to send something like { isCancelled:true} as HTTP PATCH, then your code would update the entity and take action like cancel any outstanding work.

Related

Bulk POST request without enumerating objects

I'm trying to let my API clients make a POST request that bulk modifies objects that the client doesn't have their IDs.
I'm thinking of implementing this design but I don't feel good about it, are there any better solutions than this?
POST url/objects/modify?name=foo
This request will modify all objects with the name foo
This can be a tricky thing to do with an API because it doesn't age very well.
By that I mean that over time, you might introduce more criteria for the data stored on resources (e.g., you can only set this field to "archived" if the create_time field is older than 6 months). When that happens, your bulk updates will start to only work on some resources and now you have to communicate that back to the person calling the API.
For example, for any failures you need to explain that the update worked for some resources (and list them out) but failed on others (and list them out) and the reason why for each failure (and remember you might have different failure conditions for different resources).
If you're set on going down this path, the closest thing I can think of is the "criteria-based delete" method shown here: https://google.aip.dev/165.

Which resource should I use to keep my API RESTFul?

I'm building an API to allow the client of the API to send notifications to remind a user to update an Order status. So far, there are two notifications:
when the user hasn't marked the order as received;
when the user hasn't marked the order as done.
I want to build this API to make it simple to extend to other notifications related to the order, but keep a simple URI for the clients of this API.
How can I define my resources in order to keep my API RESTFul?
I was thinking about having one of these structures:
Option 1:
POST: /api/ordernotification/receive/{id}
POST: /api/ordernotification/complete/{id}
Option 2 (omit the status from the resource and post it instead):
POST: /api/ordernotification/?id={id}&statusID={statusID}
EDIT
Option 2.1 (keeping an articulated URI, as suggested by #Jazimov):
POST: /api/ordernotification/{statusID}/{id}.
Which option is more appropriate? Is there any advantage that one option has over the other? Or are there any other option I haven't thought of?
I would go with something along these lines
POST /api/order/1234/notifications/not-received
POST /api/order/1234/notifications/not-completed
Which can later be accessed via
GET /api/order/1234/notifications/not-received
GET /api/order/1234/notifications/not-completed
Or
GET /api/order/1234/notification/8899
There's no real limitation on how semantically rich a URI can be, so you might as well take advantage of that and be explicit.
If I understand you correctly, you have two types of ordernotifications: those for notifying receive and those for notifying complete. If those are two separate data models then I think nesting them is a good idea (i.e. a table called ReceiveOrderNotification and CompleteOrderNotification). If that's the case then you may want to expose two different endpoints entirely, such as POST /api/receiveordernotification and POST /api/completeordernotification.
But I don't think that's the best you can do, given so many overlapping similarities there probably are between order notifications. Now, option 2 is more like a GET, since you're using query parameters, so with your first option let's collapse them into this:
POST: /api/ordernotification/
and then pass it some JSON data to create the notifications
{
"orderId": "orderId",
"userId": "userId",
"prompt": "not marked received/not marked done"
}
I also removed the /{id} because when you POST you create a brand new thing and the id has not been created yet, usually. Even if the client is creating an id and sending it to the API it is a good practice to leave it open so your API can handle creating a new, unique resource in its own way.
This is RESTful is because a POST creates a resource ordernotification with certain data points. Your first option made actions a resource in themselves but that's probably not represented in any data model in your backend. To be as RESTful as possible, your API endpoints should represent the database domains (tables, collections, etc). Then you let your controllers choose what service methods to use given the data sent in the request. Otherwise REST endpoints expose all the logic up front and get to be a long list of unmaintainable endpoints.
I think, to update status of already inserted records, your endpoint should be PUT instead of POST.
You can use
PUT: /api/ordernotification/:id/status/
with clients json data
{
"status": "your_status"
}
according to request data, endpoint should update the record.

How to design a RESTful API that queries info about a verb (e.g. a potential POST request)?

I'm learning how to design a RESTful API and I've come across a quandary.
Say I have a POST endpoint to perform an action. The action has a certain cost associated with it. The cost depends on what the action is, particularly, on the body of the POST. For example, given these two requests:
POST /flooblinate
{"intensity": 50, "colorful": true, "blargs": [{"norg": 43}]}
POST /flooblinate
{"intensity": 100, "colorful": false, "blargs": []}
Say the first one costs 500 and the second one costs 740.
I want to create a method which will tell me what the cost of posting the action will be. Since I am not creating or updating anything, it seems that GET is the most appropriate verb. However, a request body with GET should not have any meaning. This means that I'd have to put the data in the query string, say by URL encoding the request body to be passed to the POST:
GET /flooblinate/getCost?body=%7B%22intensity%22%3A+50%2C+%22colorful%22%3A+true%2C+%22blargs%22%3A+%5B%7B%22norg%22%3A+43%7D%5D%7D
This seems less than ideal since it's two data formats for the same thing. But the following:
POST /flooblinate/getCost
{"intensity": 50, "colorful": true, "blargs": [{"norg": 43}]}
This also seems less than ideal since it's abusing the POST verb to query information, instead of to create or update something.
What's the correct choice to make, here? Is there any third alternative? Is there a way to rethink this design fundamentally which will obviate the need to make this choice?
Personally I'm not for adding dryRyn flags. I try to avoid boolean flags in general unless they're really required.
I've two ideas to cover this scenario:
One is to introduce state on the backend site, e.g. STARTED, FINISHED. When given resource action is submitted it has STARTED state and calculated cost which cam be viewed via GET method. Such resource may be modified with PUT and PATCH methods and is submitted when given method changes its state to FINISHED. Resources that didn't change its state for given amount of time are removed are their state is changed to other terminal value.
Second idea is to introduce a new endpoint called e.g. /calculations. If you need to calculate the cost of given action you just send the same payload (via POST) to this endpoint and in return a cost is given. Then resource send may be kept on server for some established TTL or kept forever.
In all the scenarios given (including yours) there's a need to make at least two requests.
The nicest choice here seems to be to have the endpoints return the info that need querying, and add a dryRun parameter to those endpoints. Thus:
POST /flooblinate?dryRun=true
{"intensity": 50, "colorful": true, "blargs": [{"norg": 43}]}
Returns:
{"cost": 500, /* whatever else */
And then posting with dryRun=false actually commits the action.

Adding to a property in a restful API

I am in the process of designing an HTTP API.
I have a Card resource which has an Balance property, which clients can add/subtract to.
At first I thought this should be implemented as PUT, because it's a form of Update to the resource, but then I read that PUT is idempotent, but adding to an amount isn't idempotent.
As it's not a creation of an object, I think I'm left with referring to it as a controller, something like:
POST example.org/card/{card-Id}/AddToBalance
data: value=10
will add 10 to the balance.
Is there a better way?
Yea, use cases like these are not where REST excels (expressing operations, particularly when they only affect a small subset of an entities data). Your particular case is pretty simple though, you can handle it with a slight change to your verb and endpoint:
PUT example.org/card/{card-Id}/balance
{"value" : 100}
Basically read as "Update the balance of card {id} to 100". On the server side you will still need to validate the transaction, and determine wether its a valid add based off the existing value of the balance.
Design Looks good as for as REST principals are concerned.
PUT action should be Idempotent. But it depends upon you requirement
Other thing you can use PATCH, as you are just doing partial amount of Updates rather than complete replacement of resources.

Confused about Http verbs

I get confused when and why should you use specific verbs in REST?
I know basic things like:
Get -> for retrieval
Post -> adding new entity
PUT -> updating
Delete -> for deleting
These attributes are to be used as per the operation I wrote above but I don't understand why?
What will happen if inside Get method in REST I add a new entity or inside POST I update an entity? or may be inside DELETE I add an entity. I know this may be a noob question but I need to understand it. It sounds very confusing to me.
#archil has an excellent explanation of the pitfalls of misusing the verbs, but I would point out that the rules are not quite as rigid as what you've described (at least as far as the protocol is concerned).
GET MUST be safe. That means that a GET request must not change the server state in any substantial way. (The server could do some extra work like logging the request, but will not update any data.)
PUT and DELETE MUST be idempotent. That means that multiple calls to the same URI will have the same effect as one call. So for example, if you want to change a person's name from "Jon" to "Jack" and you do it with a PUT request, that's OK because you could do it one time or 100 times and the person's name would still have been updated to "Jack".
POST makes no guarantees about safety or idempotency. That means you can technically do whatever you want with a POST request. However, you will lose any advantage that clients can take of those assumptions. For example, you could use POST to do a search, which is semantically more of a GET request. There won't be any problems, but browsers (or proxies or other agents) would never cache the results of that search because it can't assume that nothing changed as a result of the request. Further, web crawlers would never perform a POST request because it could not assume the operation was safe.
The entire HTML version of the world wide web gets along pretty well without PUT or DELETE and it's perfectly fine to do deletes or updates with POST, but if you can support PUT and DELETE for updates and deletes (and other idempotent operations) it's just a little better because agents can assume that the operation is idempotent.
See the official W3C documentation for the real nitty gritty on safety and idempotency.
Protocol is protocol. It is meant to define every rule related to it. Http is protocol too. All of above rules (including http verb rules) are defined by http protocol, and the usage is defined by http protocol. If you do not follow these rules, only you will understand what happens inside your service. It will not follow rules of the protocol and will be confusing for other users. There was an example, one time, about famous photo site (does not matter which) that did delete pictures with GET request. Once the user of that site installed the google desktop search program, that archieves the pages locally. As that program knew that GET operations are only used to get data, and should not affect anything, it made GET requests to every available url (including those GET-delete urls). As the user was logged in and the cookie was in browser, there were no authorization problems. And the result - all of the user photos were deleted on server, because of incorrect usage of http protocol and GET verb. That's why you should always follow the rules of protocol you are using. Although technically possible, it is not right to override defined rules.
Using GET to delete a resource would be like having a function named and documented to add something to an array that deletes something from the array under the hood. REST has only a few well defined methods (the HTTP verbs). Users of your service will expect that your service stick to these definition otherwise it's not a RESTful web service.
If you do so, you cannot claim that your interface is RESTful. The REST principle mandates that the specified verbs perform the actions that you have mentioned. If they don't, then it can't be called a RESTful interface.