You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by Apache Wiki <wi...@apache.org> on 2010/09/11 07:11:45 UTC
[Couchdb Wiki] Update of "Throw a 404 or a redirect" by matiu
Dear Wiki user,
You have subscribed to a wiki page or wiki category on "Couchdb Wiki" for change notification.
The "Throw a 404 or a redirect" page has been changed by matiu.
The comment on this change is: tips on redirecting, throwing exceptions, and returning 404 not_found's.
http://wiki.apache.org/couchdb/Throw%20a%20404%20or%20a%20redirect
--------------------------------------------------
New page:
= Simlest ways =
== Throw a 404 error ==
To throw a 404 from inside a _show or _list func .. the easiest way is:
{{{
throw (['error', 'not_found', 'Some message like Page not found'])
}}}
That will be caught by the top level loop thing and turned into a nice response.
== Return a redirect ==
There's no top level catcher thing for redirects, so you can't *throw a redirect*, you have to 'return' it.
To do a redirect, there's a library function that will do it for you:
{{{
var redirect = require("vendor/couchapp/lib/redirect");
return redirect.permanent('http://some.new/place');
}}}
You can use the path lib to help get some neat urls, have a look at vendor/couchapp/lib/path.js source ..
What this actually does is the equivalent of:
{{{
return { code : 301, headers : { "Location" : 'http://some.new/place' } };
}}}
The 'code' is the http response code, the http response would be something like:
{{{
HTTP/1.1 301 Moved Permanently
Vary: Accept
Server: CouchDB/1.0.1 (Erlang OTP/R13B)
Location: http://foot:5984/products/dvrs/standalone-h.264-16-channel-dvr
Etag: "CYFPH3WEUO9R5B8S26QWV3NK4"
Date: Sat, 11 Sep 2010 04:51:37 GMT
Content-Type: application/json
Content-Length: 0
}}}
= Case study, Making a Redirect Throwable =
If you're deep in a lib/mystuff.js func, I use this sort of style for a certain checker function.
In this example I have different product lines in my rewrites, of the form:
{{{
[
{
"from": "/products/dvrs",
"to": "_list/dvrs",
"method": "GET"
},
{
"from": "/products/dvrs/new",
"to": "_show/dvr-new",
"method": "GET"
},
{
"from": "/products/dvrs/new",
"to": "_show/dvr-save",
"method": "POST"
},
{
"from": "/products/dvrs/*",
"to": "_show/dvr/*",
"method": "GET"
},
// Then a bunch of similar things for other product lines (like /products/cameras/ etc ..)
]
}}}
The trouble is if someone uses the wrong url for the type of product, I want to put them right, this will help keep the
search engine optimization good too. So if someone goes:
{{{
http://mysite.kom/products/cameras/id_of_a_dvr
}}}
It will call the _show/camera method with the id of a document that has {type: 'dvr'}. Which is bad because I use a
different template but also bad because SEO will freak out if it ends up in google.
To fix it I did the following:
In my _show or _list func I put:
{{{
var rewrite = require("lib/rewritehelper").init(req);
// If we're trying to use this view to see something other than a dvr, make sure we're looking at the right type
try {rewrite.checkType(doc, 'camera');} catch (e) {return e;}
}}}
I know people will yell at me for puting too much on one line. But I'm using this in all my _show and _list funcs, I
want it to be nice and short.
In my *lib/rewritehelper.js* file I check the type and all that and if it's wrong I throw an exception, which the _show
func catches and returns as is. Here's the full code for my lib function so far:
{{{
/* Helps you get the rewrites right.
Complements the rewrites.json .. really both should be updated at the same time. Saves having to update every place you
put a path to something.
*/
exports.init = function(req) {
rewrite = {};
rewrite.url4doc = function (_id, prodType) {
/* Returns a url to a product, takes doc._id and doc._type */
// See if it's a product
switch (prodType) {
case "forum-topic":
case "forum-post":
return "http://" + req.headers.Host + "/forums/" + prodType + "s/" + _id;
case "support":
return "http://" + req.headers.Host + "/support/" + prodType + "s/" + _id;
case "dvr":
case "camera":
return "http://" + req.headers.Host + "/products/" + prodType + "s/" + _id;
default:
return {code: 404, body: 'Page not found!'}
};
};
rewrite.checkType = function (doc, desiredType) {
/* Checks a document type and throws an exception that should be returned straight to the client if caught.
If no exception is raised, the check has passed */
if ((doc) && (doc.type != desiredType)) {
var newURL = rewrite.url4doc(doc._id, doc.type);
if (newURL.body == undefined) {
// If it's a url string, throw a redirect error
throw { code : 301, headers : { "Location" : newURL } };
} else {
// If it's a {code: 404} block, throw it straight
throw newURL;
}
} else {
return null;
}
}
return rewrite;
};
}}}
So the cool thing here is the 'throw' statements, if we're totally in the wrong place, I want to get out ASAP.