RESTful design: Should renamed resources block old URIs forever? [closed] - rest

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I'm trying to understand RESTful Web Services page 274 section HTTP PUT. Issuing PUT against a non-existent resource creates the resource. If PUT causes an existing resource to move, HTTP 301 (Moved Permanently) is returned with the new location. Requests to the old URI return HTTP 301, 404 or 410.
My question is about returning HTTP 301. This seems to imply that resources retain ownership of old URIs forever.
Consider: /companies/{companyName}/departments/{departmentName}
I see the following benefits of using HTTP 301:
Concurrency: If one user renames a company while another is in the process of navigating to a department, the latter will get HTTP 404 in spite of the fact that they did nothing wrong. HTTP 301 allows us to seamlessly redirect the second user to the new URI.
Bookmarks: Both humans and computers need to bookmark URIs for long-term storage. Humans post links in discussion forums. Computers use URIs for caching purposes and user preferences.
I see the following problems with HTTP 301:
Blocks long-term resource evolution: Over its life-time, department A is renamed to B, C and D. A few years later someone would like to create department A and is prevented from doing so by D. To be fair, I can't think of any practical example where this would happen so maybe it's a non-issue.
API versions limit its use: Even root resources change over time as new API versions are released and old versions are removed. What's the point of returning HTTP 301 if the client can't access the new resource the same way as it could the old?
What is the appropriate course of action? Should the URL hierarchy be modeled differently? Should the behavior/response be different?

If PUT causes an existing resource to move, HTTP 301 is returned with the new location.
Technically, you can't move resources in HTTP. If you are manipulating resources as a client, what you are doing is:
GET /oldurl
PUT /newurl
DELETE /oldurl
The server will not know that the new URL is a new location for the resource at the old URL, and there is no concept of URL persistence through redirection which can be established by the client using universal HTTP methods. If the service provides an API which allows you to move items, for example by passing certain parameters, and essentially doing the above behind the scenes but also creating a redirect in the process, then it is up to the service as to whether that redirect is overwritable with a new PUT operation or not, as well as what kind of redirect is to be used.
It's my understanding that when a post title gets renamed, we're supposed to keep track of the old name and return HTTP 301 when a client references the old address.
This has nothing to do with REST and is a manifestation of Cool URIs don't change. In a RESTful service, it is sufficient to link to the new URL via a resource or sequence of resources reachable from your service's entry point.
e.g. a HTML website is the normative example of a REST implementation
service entry point = /blog
/blog links to /blog/archive
/blog/archive links to /blog/new-post-title
since the blog service is designed to be consumed by humans using a web browser, it is expected that they may want to bookmark a URL to revisit it later. This is what redirects are for.
a machine-to-machine API has to do something similar:
service entry point = /
/ links to /companies with a rel of "http://myservice/rels/companies"
/companies links to /companies/new-company-name with a rel of "item"
No mention needs to be made of the old company name, because machines are not expected to bookmark a location, but instead to begin navigating from the entry point each time.

I would return a simple 404. This signifies that there is nothing matching the requested uri, and from the documentation, specifies:
No indication is given of whether the condition is temporary or permanent.
This way it is perfectly valid to created new resourced to replace those that existed sometime in the past.
Otherwise, if you're going to move a resource by renaming it, you could always return a 302, specifying the resource resides at a different location. You could return this status until a replacement is generated. The user must continue to use these headers to make sure the resource is still relocated:
Since the redirection might be altered on occasion, the client SHOULD continue to use the Request-URI for future requests.

Answering my own question:
I can't think of any practical example where keeping HTTP 301 forever would cause problems.
Links are not meant to survive across API versions. Resources from one version should not reference resources from another version (even using HTTP 301). If a resource's URI changes as the result of an API change, the old API should keep on using the old URI forever.
UPDATE: According to Willy Tarreau idempotency only requires the application to redirect for a short period of time. Once the client has finished retrying a request, the redirect is no longer needed (at least not for idempotency). You might want to keep redirects around for a longer period of time, to support features such as permalinks, but nothing in the specification forces you to.

Related

How to model REST URL for which there is no equivalent HTTP method?

I have customers and I want to activate and cancel their plans. I am trying to be as RESTful as possible.
Should the action to perform 'active' or 'suspend' be part of URI ?
1) POST customers/{customerId}/activatePlan/{planName}
2) POST customers/{customerId}/suspendPlan/{planName}
My problem is that both activate and cancel are verbs or actions. They do not have any equivalent HTTP action ( GET, POST, PATCH etc.)
Are my URL's restful ? if not, how to make them REST ful.
Everything is a resource on the RESTful paradigm and these resources are manipulated with one of the HTTP methods (GET, POST, PUT, DELETE, etc ...).
You can create a plan with POST:
POST customers/{customerId}/{planName}
once a plan is created we have to activate or deactivate it and here we have a couple of choices:
Using the action in the URI. We use PUT in this case as the planName resource exists (so it is an update):
PUT customers/{customerId}/{planName}/activate
Set a property on the planName resource (still a PUT as it is an update on the planName resource). The activate property in the body of the HTTP PUT request (i.e.: activate=true or activate=false):
PUT customers/{customerId}/{planName}
then you can use GET to return the status of the planName resource
GET customers/{customerId}/{planName}
and DELETE if you want to remove planName from a customer:
GET customers/{customerId}/{planName}
Are my URL's restful ?
All URI are RESTful -- REST doesn't care what spelling conventions you use for your resource identifiers.
Notice, please, that both of the following URI work exactly as you would expect them to:
https://www.merriam-webster.com/dictionary/activate
https://www.merriam-webster.com/dictionary/cancel
My problem is that both activate and cancel are verbs or actions. They do not have any equivalent HTTP action ( GET, POST, PATCH etc.)
There are a couple of different answers. Perhaps the easiest is to think about how you would design a web site that allowed you to activate and cancel plans. You would probably have a web page for this customers enrollment, and on that page might be a link with some hint, like "cancel". Clicking the link would load a new web page, with a form on it, including a bunch of fields for the customer to fill in. When the customer submits the form, the browser looks at the form, and its meta data, and figures out what request to send to the server.
A "REST API" isn't about putting your domain model on the web - it's about putting your interaction model on the web. We create a collection of documents (resources) that describe the domain, and we get useful work done by moving those documents around the network. See Jim Webber 2011.
Because we are working in the language of documents, REST interfaces are usually based on one of the following ideas
Here is a document; make local edits to your copy of the document, and send it back to the server (GET, PUT, PATCH, DELETE are the primary method tokens you see in this style)
Here is a form; fill in the details and submit it (GET and POST are the method tokens you see in these cases)
If you are unhappy with the use of POST, it may help to review Fielding 2009
POST serves many useful purposes in HTTP, including the general purpose of “this action isn’t worth standardizing.”

Use of HTTP 204 vs 200 vs 404 to safely signal that a resource doesn't exist

In my REST API I have the normal CRUD endpoints for some resources.
If I do a GET /items/42 and there is no such item, the normal behaviour would be to return a 404 NOT FOUND.
However, one scenario concerns me. In this scenario, a client needs to check if a resource (which is implicitly idenfitied by a token) exists, and if not, create it. So, the client would try to retrieve the resource, and if a 404 is received the client application would display the UI necessary for creating the item, and then proceed to POSTing the new resource. In a way, this is a special kind of resource, because since its ID is derived from other parameters, it's known even before creation. As an example, consider a user sign-up procedure; the client would ask "Do I exist? If no -> register me".
My concern is really whether I ever need to worry about "spurious" 404:s? Considering a server is usually surrounded by API gateways, reverse proxies and such, is there any risk that a 404 NOT FOUND could be produced by a surrounding entity due to some temporary error not related to the REST server itself? If so, it could trick the client into believing that the item is not created yet, and that it should now be created. Even if the resulting POST request to create the item would fail because the item already exists, this isn't very nice because the user may have entered data etc for no reason.
Is this a problem to take into account or just overly paranoid? I guess if clients can't trust a 404 to be idempotent (until the resource is created, of course), many other issues arise. Is there any actual situation where an API gateway or similar would report a 404 on its own?
If this is a valid scenario, do I need a "safer", more explicit response saying that the request definetely succeeded but the resource wasn't found, such as responding with a 200 OK with an empty JSON body or a {isRegistered: false}, a 204 NO CONTENT, or similar? This opens up for other strange things - if a request for a resource that doesn't exist would respond with a 200 accompanied by an empty body, perhaps creation of the item would be a PUT rather than a POST, etc? This seems like a can of worms... It all boils down to "Does a 404 guarantee that the given resource doesn't exist?".
404 is pretty unambiguous : the resource wasn't found and it's a client error (4xx). Normally, server-side errors (5xx) can't interfere and create spurious 404's here.
As an alternative, if the resource to be created is linked to another resource in a unique way, you could use OPTIONS to ask the server if it already exists.
For instance :
OPTIONS /visitors/7883930/user-account
=> Allow: POST,OPTIONS (doesn't exist)
=> Allow: GET,OPTIONS (exists)
The key here is to have a URI that allows accessing the resource without knowing its ID. It is not always possible though.

How should client of Restful API handle http status 301 redirect upon POST?

Question
How should a well-designed application handle 301 "moved permanently" redirects upon http POST to restful api?
Context
Our hosted application offers a restful api
We have a customer extensively who uses our restful api in their own 'on-premise' application [fwiw, installed at dozens of sites-- with no easy way to update]
We are migrating our application to a new data centers and in the process we will switch them (and others) from 'plain text http' to 'ssl-encrypted https'. [The physical location data center of course is irrelevant, but the new data center has more stringent security rules and thus mandates https]
Our front end (haproxy/nginx) will send a 301 'Moved Permanently'
This 301 redirect preserves query parameters but loses post data
I know that "restful api's should be permanent", but, merde arrive (that's shit happens in French)--Empires crumble, Berlin Wall falls, Oracle buys Sun etc.
The Problem
Their application makes HTTP post calls to our restful api. When the front end returns 'http status 301', their application does not 're-post' to the new url, and the update fails.
Questions
How should error handling handle 301's as well as other http statuses? ( pseudocode will suffice)
Should our 'front end' do something different for '301'?
To fulfill your "well-designed" requirement in the sense of "pure RESTfulness", the client should re-send the request to the new URI. A response code of 301 indicate the resource has moved, and cannot be used to fulfill the request, so there's really no fallback position.
If the client attempts to re-post, but loses data, that's a client bug. The "correct" behavior of a client varies by your requirements: it could treat the redirect as a recoverable error case, and repost transparently; it could repost while instructing the user to update the endpoint; or it could fail with an appropriate error message.

Non-SEO anti-spoofing external link redirect: Status code?

I've read several documents on the merits of the different HTTP redirect status codes, but those've all been very SEO-centric. I've now got a problem where search-engines don't factor in, because the section of the site in question is not publicly viewable.
However, we do want our website to be as accurate / helpful with meta-data as possible, especially for accessibility reasons.
Now, our application takes external links provided by third parties and routes them across an anti-spoofing page with a disclaimer. Since this redirector page can effectively also be embedded via an Ajax call in certain constellations, we also want to strip any query parameters from the referer (for privacy purposes; the target site has no business finding out what internal page the user was on before).
To do this, the confirmation button triggers a server-side script which in turn redirects (rather than just opening the page for the user).
So much as to why our anti-spoofing disclaimer page ends up triggering a redirect.
The question is:
Does it effectively make any difference which status code I use? Do non-typical browsers (e.g. screen-readers) care? If so, what's the best practise for such redirects? The most semantically sound, if you so will? They all seem various degrees of insincere to me.
I'm thinking of a 302 - but as it makes no sense trying to bookmark the page (it's protected with a crsf token), so there's probably no harm in a 301, either, is there? So I'm wondering if there's a reason for me to prefer the one over the other.
Hmm. Here's the list. 301 sounds okay (emphasis mine):
The requested resource has been assigned a new permanent URI and any future references to this resource SHOULD use one of the returned URIs. Clients with link editing capabilities ought to automatically re-link references to the Request-URI to one or more of the new references returned by the server, where possible.
302 doesn't fit n my opinion:
The requested resource resides temporarily under a different URI
However, my favourite is 303 see other:
The response to the request can be found under a different URI and SHOULD be retrieved using a GET method on that resource. This method exists primarily to allow the output of a POST-activated script to redirect the user agent to a selected resource. The new URI is not a substitute reference for the originally requested resource.
But that might be so rare (I've never seen it used in the wild) that some clients may not understand it - which would render your desire for maximum compatibility moot. 301 is probably the closest choice.

How do you implement resource "edit" forms in a RESTful way?

We are trying to implement a REST API for an application we have now. We want to expose read/write capabilities for various resources using the REST API. How do we implement the "form" part of this? I get how to expose "read" of our data by creating RESTful URLs that essentially function as method calls and return the data:
GET /restapi/myobject?param=object-id-maybe
...and an XML document representing some data structure is returned. Fine.
But, normally, in a web application, an "edit" would involve two requests: one to load the current version of the resources and populate the form with that data, and one to post the modified data back.
But I don't get how you would do the same thing with HTTP methods that REST is sort of mapped to. It's a PUT, right? Can someone explain this?
(Additional consideration: The UI would be primarily done with AJAX)
--
Update: That definitely helps. But, I am still a bit confused about the server side? Obviously, I am not simply dealing with files here. On the server, the code that answers the requests should be filtering the request method to determine what to do with it? Is that the "switch" between reads and writes?
There are many different alternatives you can use. A good solution is provided at the microformats wiki and has also been referenced by the RESTful JSON crew. As close as you can get to a standard, really.
Operate on a Record
GET /people/1
return the first record
DELETE /people/1
destroy the first record
POST /people/1?_method=DELETE
alias for DELETE, to compensate for browser limitations
GET /people/1/edit
return a form to edit the first record
PUT /people/1
submit fields for updating the first record
POST /people/1?_method=PUT
alias for PUT, to compensate for browser limitations
I think you need to separate data services from web UI. When providing data services, a RESTful system is entirely appropriate, including the use of verbs that browsers can't support (like PUT and DELETE).
When describing a UI, I think most people confuse "RESTful" with "nice, predictable URLs". I wouldn't be all that worried about a purely RESTful URL syntax when you're describing web UI.
If you're submitting the data via plain HTML, you're restricted to doing a POST based form. The URI that the POST request is sent to should not be the URI for the resource being modified. You should either POST to a collection resource that ADDs a newly created resource each time (with the URI for the new resource in the Location header and a 202 status code) or POST to an updater resource that updates a resource with a supplied URI in the request's content (or custom header).
If you're using an XmlHttpRequest object, you can set the method to PUT and submit the data to the resource's URI. This can also work with empty forms if the server supplies a valid URI for the yet-nonexistent resource. The first PUT would create the resource (returning 202). Subsequent PUTs will either do nothing if it's the same data or modify the existing resource (in either case a 200 is returned unless an error occurs).
The load should just be a normal GET request, and the saving of new data should be a POST to the URL which currently has the data...
For example, load the current data from http://www.example.com/record/matt-s-example and then, change the data, and POST back to the same URL with the new data.
A PUT request could be used when creating a new record (i.e. PUT the data at a URL which doesn't currently exist), but in practice just POSTing is probably a better approach to get started with.