You need to be added to the ContributorsGroup to edit the wiki. But don't worry! Just email any Mailing List or grab us on IRC and let us know your user name.
Advanced Shows and Lists: Throwing Redirects
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.