CouchDB’s show functions are a RESTful API inspired by a similar feature in Lotus Notes. In a nutshell, they allow you to serve documents to clients, in any format you choose.
A show function builds an HTTP response with any Content-Type, based on a stored JSON document. For Sofa, we’ll use them to show the blog post permalink pages. This will ensure that these pages are indexable by search engines, as well as make the pages more accessible. Sofa’s show function displays each blog post as an HTML page, with links to stylesheets and other assets, which are stored as attachments to Sofa’s design document.
Hey, this is great—we’ve rendered a blog post! See Figure 13-1.
The complete show function and template will render a static, cacheable resource that does not depend on details about the current user or anything else aside from the requested document and Content-Type. Generating HTML from a show function will not cause any side effects in the database, which has positive implications for building simple scalable applications.
Let’s look at the source code. The first thing we’ll see is the JavaScript function body, which is very simple—it simply runs a template function to generate the HTML page. Let’s break it down:
function
(
doc
,
req
)
{
// !json templates.post
// !json blog
// !code vendor/couchapp/template.js
// !code vendor/couchapp/path.js
We’re familiar with the !code
and
!json
macros from Chapter 12.
In this case, we’re using them to import a template and some metadata
about the blog (as JSON data), as well as to include link and template
rendering functions as inline code.
Next, we render the template:
return
template
(
templates
.
post
,
{
title
:
doc
.
title
,
blogName
:
blog
.
title
,
post
:
doc
.
html
,
date
:
doc
.
created_at
,
author
:
doc
.
author
,
The blog post title, HTML body, author, and date are taken from the document, with the blog’s title included from its JSON value. The next three calls all use the path.js library to generate links based on the request path. This ensures that links within the application are correct.
assets
:
assetPath
(),
editPostPath
:
showPath
(
'edit'
,
doc
.
_id
),
index
:
listPath
(
'index'
,
'recent-posts'
,{
descending
:
true
,
limit
:
5
})
});
}
So we’ve seen that the function body itself just calculates some values (based on the document, the request, and some deployment specifics, like the name of the database) to send to the template for rendering. The real action is in the HTML template. Let’s take a look.
The template defines the output HTML, with the exception of a few
tags that are replaced with
dynamic content. In Sofa’s case, the dynamic tags look like
<%= replace_me %>
, which is a common templating
tag delimiter.
The template engine used by Sofa is adapted from John Resig’s blog post, “JavaScript Micro-Templating”. It was chosen as the simplest one that worked in the server-side context without modification. Using a different template engine would be a simple exercise.
Let’s look at the template string. Remember that it is included in
the JavaScript using the CouchApp !json
macro, so
that CouchApp can handle escaping it and including it to be used by the
templating engine.
<!DOCTYPE html>
<html>
<head>
<title>
<
%= title %> :<
%= blogName %></title>
This is the first time we’ve seen a template tag in action—the
blog post title, as well as the name of the blog as defined in
blog.json are both used to craft the HTML
<title>
tag.
<link
rel=
"stylesheet"
href=
"../../screen.css"
type=
"text/css"
>
Because show functions are served from within the design document path, we can link to attachments on the design document using relative URIs. Here we’re linking to screen.css, a file stored in the _attachments folder of the Sofa source directory.
</head>
<body>
<div
id=
"header"
>
<a
id=
"edit"
href=
"<%= editPostPath %>"
>
Edit this post</a>
<h2><a
href=
"<%= index %>"
>
<
%= blogName %></a></h2>
Again, we’re seeing template tags used to replace content. In this case, we link to the edit page for this post, as well as to the index page of the blog.
</div>
<div
id=
"content"
>
<h1>
<
%= title %></h1>
<div
id=
"post"
>
<span
class=
"date"
>
<
%= date %></span>
The post title is used for the <h1>
tag,
and the date is rendered in a special tag with a class of
date
. See Dynamic Dates for
an explanation of why we output static dates in the HTML instead of
rendering a user-friendly string like “3 days ago” to describe the
date.
<div
class=
"body"
>
<
%= post %></div>
</div>
</div>
</body>
</html>
In the close of the template, we render the post HTML (as converted from Markdown and saved from the author’s browser).
When running CouchDB behind a caching proxy, this means each show
function should have to be rendered only once per updated document.
However, it also explains why the timestamp looks like 2008/12/25
23:27:17 +0000
instead of “9 days ago.”
It also means that for presentation items that depend on the current time, or the identity of the browsing user, we’ll need to use client-side JavaScript to make dynamic changes to the final HTML.
$
(
'.date'
).
each
(
function
()
{
$
(
this
).
text
(
app
.
prettyDate
(
this
.
innerHTML
));
});
We include this detail about the browser-side JavaScript implementation not to teach you about Ajax, but because it epitomizes the kind of thinking that makes sense when you are presenting documents to client applications. CouchDB should provide the most useful format for the document, as requested by the client. But when it comes time to integrate information from other queries or bring the display up-to-date with other web services, by asking the client’s application to do the lifting, you move computing cycles and memory costs from CouchDB to the client. Since there are typically many more clients than CouchDBs, pushing the load back to the clients means each CouchDB can serve more users.
Get CouchDB: The Definitive Guide now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.