Write once semantics for REST interface - rest

We have a REST interface that allows clients to create a Product resource. The Product can be associated with different kind of metadata.
/Product/{id}/metadata/{md_type}
The team wants a particular type of metadata to be written only ONCE. Subsequent updates should be rejected.
Currently, a PUT request is used to create the metadata. The metadata is not assigned an ID. It is immutable. The PUT request is rejected if the metadata already exist.
Using PUT feels like a violation of REST semantics. What is the most RESTful way to handle the situation?

Using PUT feels like a violation of REST semantics. What is the most RESTful way to handle the situation?
Using PUT is perfect here.
The simplest answer is that you are missing the fact that this is a Conditional Request; if the client were to send its request with an If-None-Match header, then all of the generic handling of conditional requests would "just work", with the server returning a 412 Precondition Failed if the resource already has a representation.
If the client doesn't include the If-None-Match header, then I don't think 412 is appropriate. Perhaps 405 Method Not Allowed, or 409 Conflict; 403 Forbidden is on point but may confuse humans who think that must refer to a credentials problem.
Rejecting updates on subsequent PUTs violates the principal of least surprise for RESTful interfaces.
No, it doesn't. Because PUT defines and constrains the semantics of the request, it doesn't obligate the server to fulfill the request.

Related

Restful way to delete a write-protected resource

In my API, resources can be write-protected. Trying to DELETE such a resource will return a 409 (Conflict) response.
For users that are allowed to change the protected state of a resource, I want to introduce the option to delete protected resources with one request. How should this option be passed?
Possible solutions:
Request body -- should not be used with delete requests
Query parameter -- changes the URI, so technically refers to a different resource
Custom header -- generally discouraged
Standard header -- none apply
Two requests -- not atomic, things could happen in-between (eg another user modifying the resource)
Alternative endpoint -- not restful?
Related Questions
In REST API, can DELETE methods have parameters?
Answer says yes to query parameters, but asks about deleting a subset of a collection
REST, HTTP DELETE and parameters
Asks about a confirmation flag, answers say it should be handled in UI instead of API
Also says it violates the uniform interface principle, but doesn't explain why and how
Also argues that using query parameters would violate URI principle
RESTful Alternatives to DELETE Request Body
Accepted answer says to use the body, but many commenters report technical issues
Query parameters are suggested as alternative, concern about URI principle is raised
Is an entity body allowed for an HTTP DELETE request?
Says not to use the request body, even if technically allowed
Whats the best way to design DELETE for a restful resource
Says to use query parameters, but again in a subset context
For users that are allowed to change the protected state of a resource, I want to introduce the option to delete protected resources with one request. How should this option be passed?
If the meaning of the request message is consistent with HTTP DELETE, then you should probably just use HTTP DELETE, rather than trying to invent a dialect that allows you to discriminate between DELETE and no-no-I-really-mean-it-DELETE.
Are your message semantics consistent with HTTP DELETE? You may want to consider this observation in RFC 9110
Relatively few resources allow the DELETE method -- its primary use is for remote authoring environments, where the user has some direction regarding its effect.
DELETE is the method token we send to a web server when we want that server to stop sharing representations of a resource. It's semantics are rooted in the transfer of documents over a network domain.
On the other hand, if the message isn't consistent with HTTP DELETE, then you should consider using HTTP POST.
POST serves many useful purposes in HTTP, including the general purpose of “this action isn’t worth standardizing.” -- Fielding, 2009
Here's a way of thinking about the distinction: our goal in creating a "REST API" is to create a facade that disguises our domain service as an HTTP-aware document store.
If what the client is really doing is marking a document as hidden in the store; and as a side effect of that we may make a bunch of changes in our domain service, then DELETE is appropriate.
On the other hand, if what the client is really doing is sending information to our domain service, and as a side effect some documents are going to be hidden, then POST is appropriate.

Are PUT and DELETE HTTP methods indispensable just because of their idempotency property?

I have a REST API and I want to handle all HTTP requests via POST request.
Is there any performance or other kind of issue in using just POST to perform all CRUD operations requested by a user, which sends a JSON containing some data and the operation to be performed?
Technically, the HTML used in the Web only supports GET and POST and this is more or less the reference implementation of a REST architecture.
So, while this is possible I wouldn't advocate for something like that as the idempotency property of PUT and DELETE provide some other benefits in case of network issues where a client can automatically resend the request regardless whether the initial request, whose response might have just got lost mid-way, actually performed its task or not. The result should always be an updated/created resource or a removed URI mapping to the actual resource (or even a removal of the actual resource) as DELETE technically just removes the URI mapping.
In regards to put some operations in the payload, it depends. This actually sounds very RPCy to me, similar to SOAP i.e. If the operation however is defined by a well-defined media-type, like in the JSON Patch case, I guess this is not wrong. Similar to the Web, however, a server should use some resource that is able to teach a client on how to build up a request, like HTML does with forms. This will not only teach the client on what fields the server supports for the target resource but also where to send the request to as well as the media-type and HTTP operation to use, which might be fixed to POST as in the HTML case.

Should I use a POST request to send a retrieval request to my server for a large array of ids?

I read the following posts; however, I still haven't found a conclusive answer to my question.
When do you use POST and when do you use GET?
How should I choose between GET and POST methods in HTML forms?
So why should we use POST instead of GET for posting data? [duplicate]
I want to make a HTTP request to my server to retrieve some data based on an array of ids that I will pass to the server. Since each id will have a length of 23 characters, sending 100 of these ids as query parameters of a GET request will exceed the character length limit of some browsers. Since a standard GET request is not feasible due to URL limits, I have been considering my other options.
Option 1: Use request body of HTTP GET request (not advisable according to following SO thread)
HTTP GET with request body
Option 2: Use body of HTTP POST request to send the array of Ids. This is the method that Dropbox appear to have used for their public-facing API.
I know that POST requests should be reserved for requests that are not idempotent and in my case, I should be using a GET request because the query is idempotent. I also know that REST is purely a guideline and since this API will only be consumed by me, I can do whatever I like; however, I thought I'd get a second opinion on the matter before I commit to any decision.
So, what should I do in my situation? Are there better alternatives that I have yet to discover and is there anything I should consider if I do use a POST request?
So, what should I do in my situation?
First step is to review the HTTP Method Registry, which is defined within RFC 7231
Additional methods, outside the scope of this specification, have been standardized for use in HTTP. All such methods ought to be registered within the "Hypertext Transfer Protocol (HTTP) Method Registry" maintained by IANA
The registry is currently here: https://www.iana.org/assignments/http-methods/http-methods.xhtml
So you can review methods that have already been standardized, to see if any of them have matching semantics.
In your case, you are trying to communicate a query with a message-body. As a rule, queries are not merely idempotent but also safe.
A quick skim of the registry might lead you to consider SEARCH
SEARCH is a safe method; it does not have any significance other than executing a query and returning a query result
That looks like a good option, until you read through the specification carefully, and notice the constraints relating the message body. In short, WebDAV probably isn't what you want.
But maybe something else is a fit.
A second option is to consider your search idiom to be a protocol. You POST (or PUT, or PATCH) the ids to the server to create a resource, and then GET a representation of that resource when you want the results.
By itself, that's not quite the single call and response that you want. What it does do is set you up to be thinking about how to be returning a representation of query result resource. In particular, you can use Content-Location to communicate to intermediaries that the response body is in fact the representation of a resource.
I know that POST requests should be reserved for requests that are not idempotent
That's not quite right. When making requests that align with the semantics of another method, we prefer using that other method so that intermediate components can take advantage of the semantics: an idempotent request can be tried, a safe request can be pre-fetched, and so on. Because POST doesn't offer those guarantees, clients cannot take advantage of them even if they happen to apply.
Depending on how you need to manage the origin servers URI namespace, you could use PUT -- conceptually, the query and the results are dual to one another, so can be thought of as two different representations of the same thing. You might manage this with media types - one for the request, a different one for the response.
That gets you back idempotent, but it doesn't get you safe.
I suspect safe requests with payloads are always going to be a problem; the Vary header in HTTP doesn't have an affordance to allow the server to announce that the returned representation depends on the request body (in part because GET isn't supposed to have a request body), so it's going to be difficult for an intermediate component to understand the caching implications of the request body.
I did come across another alternative method from another SO thread, which was to tunnel a GET request using POST/PUT method by adding the X-HTTP-Method-Override request header. Do you think its a legitimate solution to my question?
No, I don't think it solves your problem at all. X-HTTP-Method-Override (and its variant spellings) are for method tunneling, not method-override-the-specification-ing. X-HTTP-Method-Override: GET tells the server that the payload has no defined semantics, which puts you back into the same boat as just using a GET request.

REST HTTP status code if DELETE impossible

My question is quite a generic one about HTTP status code when a DELETE is impossible on the resource (but not regarding user's rights).
We have a RESTful API on a type of resource.
The DELETE method is authorized on the resource however under some conditions a resource cannot be deleted (if there are data binded to this resource).
What is the correct HTTP status code to return to the client in this situation?
Here are some of the possibilities I gathered and why it seems inappropriate in my case :
403 (Forbidden) : Seems mostly related with user's rights.
405 (Method Not Allowed) : Seems like the API is not designed to respond to this method for this type of resource.
409 (Conflict) : Seems appropriate but the client should have the possibility to resolve the conflict with the API but that's not the case here.
Update : The data binding that prevents the resource to be deleted cannot be changed via the REST API. However the resource can be "freed" via other way as the database from which the data comes from is also accessed by other apps that may change the state of a resource (an SQL DELETE in the DB can always do that).
I'd say 409 is the most appropriate, given it's wording in the RFC:
The 409 (Conflict) status code indicates that the request could not
be completed due to a conflict with the current state of the target
resource. This code is used in situations where the user might be
able to resolve the conflict and resubmit the request. The server
SHOULD generate a payload that includes enough information for a user
to recognize the source of the conflict.
(emphasis mine)
Based on my understanding of the description in the question, the reason for DELETE not being allowed is exactly a conflict with the current state of the target resource. As indicated in the RFC, the response payload can give an indication of the reason and, optionally, the user might be able to resolve it. I don't see anything in the spec that makes 409 inappropriate just because the API doesn't offer a conflict resolution possibility.
A 409 Conflict response is definitely wrong if the client can't resolve the conflict and delete the request later. That is, unless the resource has state tracking whether it can be deleted or not, 409 Conflict is not a good fit.
A 403 Forbidden doesn't necessarily mean not authorized:
However, a request might be forbidden for reasons unrelated to the credentials.    -- RFC 7231
The implication is usually there, though. You can use this code, but it may cause some confusion. It'll be especially tricky if the method actually requires authorization also - you'll need a code or something in the response indicating whether the failure was related to authorization or the resource being non-deletable.
I think that 405 Method Not Allowed is the correct way to go.
The 405 (Method Not Allowed) status code indicates that the method received in the request-line is known by the origin server but not supported by the target resource.    -- RFC 7231
The method DELETE is not supported for this resource. That sounds exactly like what you're describing. The HTTP spec doesn't really have a concept of a type of resource - just a resource. It happens that people group individual resources under the same endpoint for sanity, but that's just a convenience for developers and users. As far as the HTTP spec is concerned, /widgets/12 and /widgets/15 and /widgets/3453 are three different resources. The fact that the same object represents all three of those resources on the server is completely irrelevant. I think that's the "type" you're thinking of, but to HTTP that's just an implementation detail.

REST API best HTTP Status response for illegal operation

I'm creating a REST API in PHP.
When the client may try to perform an action, which is unavailable, for example, it tries to change a property of the resource which is not passable: for example, tries to change the value of the "country" property to "Julius Caesar":
What HTTP status code should I send back with the response? I'm speculating between 403 and 409.
I don't know if 403 Forbidden is only related to user permissions or can I use for this purpose?
In what situation should I use 409 Conflict?
To summarize what is the proper HTTP response status to an illegal operation?
I think you should use a 403 Forbidden here.
From the HTTP specification:
The server understood the request, but is refusing to fulfill it.
Authorization will not help and the request SHOULD NOT be repeated. (...)
As you are refusing to change the value of "country", this is the status code you want to return. The client is not authorized to change the resource's country.
409 Conflict is not appropriate in this case. The 409 status is to be used when for instance somebody sends a request to update a resource, but their version of the resource is outdated because the resource has been modified in the meantime. In other words, there is a conflict between the client's data and the data on the server. This has nothing to do with allowing certain properties of the resource to be changed.
The request could not be completed due to a conflict with the current
state of the resource. This code is only allowed in situations where
it is expected that the user might be able to resolve the conflict and
resubmit the request. The response body SHOULD include enough
information for the user to recognize the source of the conflict.
Ideally, the response entity would include enough information for the
user or user agent to fix the problem; however, that might not be
possible and is not required.
Conflicts are most likely to occur in response to a PUT request. For
example, if versioning were being used and the entity being PUT
included changes to a resource which conflict with those made by an
earlier (third-party) request, the server might use the 409 response
to indicate that it can't complete the request. In this case, the
response entity would likely contain a list of the differences between
the two versions in a format defined by the response Content-Type.
(emphasis mine)
In this situation, I usually opt for a 400 Bad Request. I'm not sure if a more specific 400 range status code would fit better, however I would not use 403. For me, a 403 is security related, and should not be used for request payload validation errors.
As for 409 Conflict, I usually use this if the request is valid, but the state change is somehow illegal. However, I have seen it used in other contexts as well.
In the end, as long as you are consistent across your API (and document the meaning of the return status codes), you have some flexibility to decide how you want to express the error.