Show Functions

ショウ機能

CouchDB’s JSON documents are great for programmatic access in most environments. Almost all languages have HTTP and JSON libraries, and in the unlikely event that yours doesn’t, writing them is fairly simple. However, there is one important use case that JSON documents don’t cover: building plain old HTML web pages. Browsers are powerful, and it’s exciting that we can build Ajax applications using only CouchDB’s JSON and HTTP APIs, but this approach is not appropriate for most public-facing websites.

CouchDBがもつJSONドキュメントはほとんどの環境での機械的なアクセスにおいて扱いやすいものです。殆どすべての言語でHTTPやJSONのライブラリが利用できます。しかし、HTMLのウェブページを構築する方法などで紹介しきれていない重要なことがあります。ブラウザはパワフルです。そして、CouchDBのJSON とHTML のAPIだけを使ったAjaxアプリケーションを構築できることは、とてもエキサイティングです。しかし、この方法は殆どの公式なWebサイトで適用されていません。

HTML is the lingua franca of the web, for good reasons. By rendering our JSON documents into HTML pages, we make them available and accessible for a wider variety of uses. With the pure Ajax approach, visually impaired visitors to our blog stand a chance of not seeing any useful content at all, as popular screen-reading browsers have a hard time making sense of pages when the content is changed on the fly via JavaScript. Another important concern for authors is that their writing be indexed by search engines. Maintaining a high-quality blog doesn’t do much good if readers can’t find it via a web search. Most search engines do not execute JavaScript found within a page, so to them an Ajax blog looks devoid of content. We also mustn’t forget that HTML is likely more friendly as an archive format in the long term than the platform-specific JavaScript and JSON approach we used in previous chapters. Also, by serving plain HTML, we make our site snappier, as the browser can render meaningful content with fewer round-trips to the server. These are just a few of the reasons it makes sense to provide web content as HTML.

HTMLはよい意味で、webの国際語とも言えます。私たちはHTMLページにJSONドキュメントをレンダリングすることで、広く様々な使い方として有効でアクセス可能なものにします。純粋なAjaxのアプローチでは、ブログへの訪れた目の不自由な訪問者は有益な内容を全く見ることが出来なくても我慢するしかありません。有名な画面音読ブラウザは、ページの内容がJavaScriptを通してこっそりと更新されたとき、ページの意図をくみとるのに時間を要します。筆者の他の重要な関心毎はそこで書かれていることがサーチエンジンによってインデックスされるということです。高品質すぎるブログを管理することは、利用者が検索をつかってそれを見つけることができないという点でとてもよいわけではないのです。殆どのサーチエンジンがページの中にあるJavaScriptを実行しません。それゆえAjaxで作られたブログはコンテンツが欠けているように見えます。私たちはまた、前章で使っていたようなJavaScriptやJSONといったプラットフォーム依存のものよりも長い期間保管できるフォーマットとして、HTMLがより親しみがあるということを忘れてはいけません。さらに、HTMLを提供することで、私たちはすぐにサイトを作り、ブラウザは数回のサーバとの往復で意味のあるコンテンツを表示できます。たった数個の理由からも、webコンテンツがHTMLで作られ提供されることにうなずけます。

The traditional way to accomplish the goal of rendering HTML from database records is by using a middle-tier application server, such as Ruby on Rails or Django, which loads the appropriate records for a user request, runs a template function using them, and returns the resulting HTML to the visitor’s browser. The basics of this don’t change in CouchDB’s case; wrapping JSON views and documents with an application server is relatively straightforward. Rather than using browser-side JavaScript to load JSON from CouchDB and rendering dynamic pages, Rails or Django (or your framework of choice) could make those same HTTP requests against CouchDB, render the output to HTML, and return it to the browser. We won’t cover this approach in this book, as it is specific to particular languages and frameworks, and surveying the different options would take more space than you want to read.

データベースのレコードからHTMLを生成するための伝統的な方法はアプリケーションサーバを使うことです。例えばRuby on RailsやDjangoなどで、ユーザの要求に対応したレコードを読み込み、テンプレートを適用してブラウザへHTMLとして戻します。この基本的なことはCouchDBの場合でも変わりません。アプリケーションサーバでのJSONビューとドキュメントのラッピングは比較的単純です。ブラウザサイドのJavaScriptをCouchDBからJSONを読み込む方法として使うことや動的なページを表示するというよりは、RailsやDjango(またはあなたが選んだフレームワーク)はCouchDBに反してHTTPリクエストを作りHTMLへの出力を表示し、ブラウザへそれを戻すことができました。この本では特定の言語やフレームワークのことや、たくさんのページ数を要してしまうような別の選択肢に関することについては述べません。

CouchDB includes functionality designed to make it possible to do most of what an application tier would do, without relying on additional software. The appeal of this approach is that CouchDB can serve the whole application without dependencies on a complex environment such as might be maintained on a production web server. Because CouchDB is designed to run on client computers, where the environment is out of the control of application developers, having some built-in templating capabilities greatly expands the potential uses of these applications. When your application can be served by a standard CouchDB instance, you gain deployment ease and flexibility.

CouchDBは追加のアプリケーションソフトウェアに頼ることなく、アプリケーション階層がすることのほとんどを行えるようにデザインされています。この方法の良いところは、Webサーバ製品を管理しないといけないような複雑な環境への依存もなくなり、CouchDBがすべてのアプリケーションを提供できることです。CouchDBはアプリケーション開発者の管理から外れた環境であるクライアントマシン上で動作するように設計されています。そのため、アプリケーションの本来の利用方法をうまく拡張するような仕組みとしていくつかの組み込みのテンプレート機能を持っています。CouchDBでアプリケーションを提供するような場合は、簡単で柔軟な提供方法を実感できるでしょう。

The Show Function API

ショウ機能のAPI

Show functions, as they are called, have a constrained API designed to ensure cacheability and side effect–free operation. This is in stark contrast to other application servers, which give the programmer the freedom to run any operation as the result of any request. Let’s look at a few example show functions.

ショウ機能はキャッシュや無影のない操作を可能とするためにデザインされたAPIを持っています。これは他のアプリケーションサーバと対照的な部分で、リクエストの結果としてあらゆる操作を実行するための自由がプログララマに与えられています。いくつかのショウ機能の例を見てみましょう。

The most basic show function looks something like this:

殆どの基本的なshow関数は以下のようなものです。

function(doc, req) {
  return '<h1>' + doc.title + '</h1>';
}

When run with a document that has a field called title with the content “Hello World,” this function will send an HTTP response with the default Content-Type of text/html, the UTF-8 character encoding, and the body <h1>Hello World</h1>.

titleフィールドに"Hello World"が入っているようなドキュメントと実行したとき、この関数はHTTPレスポンスのContent-Typeをデフォルト値のtext/htmlで返します。UTF-8文字エンコードで、その本文は<h1>Hello World</h1>です。

The simplicity of the request/response cycle of a show function is hard to overstate. The most common question we hear is, “How can I load another document so that I can render its content as well?” The short answer is that you can’t. The longer answer is that for some applications you might use a list function to render a view result as HTML, which gives you the opportunity to use more than one document as the input of your function.

show関数のリクエスト/レスポンスのサイクルの単純さは明確です。良くある質問は"どうすれば別のドキュメントをロードし、その内容を表示できるのか?”です。簡潔に答えるなら、”出来ない”です。細かく言えば、アプリケーションで、HTMLのような結果を表示するためにリスト関数を使うことができます。それにより、一つ以上のドキュメントを関数のインプットとして使うことができます。

The basic function from a document and a request to a response, with no side effects and no alternative inputs, stays the same even as we start using more advanced features. Here’s a more complex show function illustrating the ability to set custom headers:

ドキュメントとリクエストから、副作用や他の代替の入力もないようなレスポンスを行う基本的な関数は、更なる進んだ機能を使い始めるのと同じです。以下にカスタムヘッダーをセットするための方法を記載したもう少し複雑なshow関数を示します。

function(doc, req) {
  return {
    body : '<foo>' + doc.title + '</foo>',
    headers : {
      "Content-Type" : "application/xml",
      "X-My-Own-Header": "you can set your own headers"
    }
  }
}

If this function were called with the same document as we used in the previous example, the response would have a Content-Type of application/xml and the body <foo>Hello World</foo>. You should be able to see from this how you’d be able to use show functions to generate any output you need, from any of your documents.

もしこの関数が、前の例で使っていたように同じドキュメントに対して呼ばれるなら、レスポンスは"Content-Type"がapplication/xmlで、本文が<foo>Hello World</foo>となるでしょう。この例により、ドキュメントから必要とするアウトプットを生成するために、どのようにshow関数を使うことができるかを確認できるでしょう。

Popular uses of show functions are for outputting HTML page, CSV files, or XML needed for compatibility with a particular interface. The CouchDB test suite even illustrates using show functions to output a PNG image. To output binary data, there is the option to return a Base64-encoded string, like this:

show関数の良くある使い方は、HTMLページ、CSVファイル、特殊なインタフェースの互換性のために必要なXMLなどの生成です。CouchDBテストスイートではPNGイメージを出力するためにshow関数を使うような場面を想定しています。バイナリデータの出力のため、以下のようなBase64エンコードの文字を返すためのオプションがあります。

function(doc, req) {
  return {
    base64 :
      ["iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAsV",
        "BMVEUAAAD////////////////////////5ur3rEBn////////////////wDBL/",
        "AADuBAe9EB3IEBz/7+//X1/qBQn2AgP/f3/ilpzsDxfpChDtDhXeCA76AQH/v7",
        "/84eLyWV/uc3bJPEf/Dw/uw8bRWmP1h4zxSlD6YGHuQ0f6g4XyQkXvCA36MDH6",
        "wMH/z8/yAwX64ODeh47BHiv/Ly/20dLQLTj98PDXWmP/Pz//39/wGyJ7Iy9JAA",
        "AADHRSTlMAbw8vf08/bz+Pv19jK/W3AAAAg0lEQVR4Xp3LRQ4DQRBD0QqTm4Y5",
        "zMxw/4OleiJlHeUtv2X6RbNO1Uqj9g0RMCuQO0vBIg4vMFeOpCWIWmDOw82fZx",
        "vaND1c8OG4vrdOqD8YwgpDYDxRgkSm5rwu0nQVBJuMg++pLXZyr5jnc1BaH4GT",
        "LvEliY253nA3pVhQqdPt0f/erJkMGMB8xucAAAAASUVORK5CYII="].join(''),
    headers : {
      "Content-Type" : "image/png"
    }
  };
}

This function outputs a 16×16 pixel version of the CouchDB logo. The JavaScript code necessary to generate images from document contents would likely be quite complex, but the ability to send Base64-encoded binary data means that query servers written in other languages like C or PHP have the ability to output any data type.

この関数では、16x16ピクセルのCouchDBロゴを出力します。ドキュメントの内容からイメージを生成するために必要となるJavaScriptコードは極めて複雑になりそうですが、Base64エンコードのバイナリデータを送ることが出来る機能が意味するのは、他の言語(例えばC, PHP)でクエリーサーバーが書かれていても、どのようなデータ形式でもアウトプットできる機能を持つということです。

Side Effect–Free

副作用を無くす

We’ve mentioned that a key constraint of show functions is that they are side effect–free. This means that you can’t use them to update documents, kick off background processes, or trigger any other function. In the big picture, this is a good thing, as it allows CouchDB to give performance and reliability guarantees that standard web frameworks can’t. Because a show function will always return the same result given the same input and can’t change anything about the environment in which it runs, its output can be cached and intelligently reused. In a high-availability deployment with proper caching, this means that a given show function will be called only once for any particular document, and the CouchDB server may not even be contacted for subsequent requests.

show関数の副作用となる主な制約について述べました。これはドキュメントをアップデートしたり、バックグラウンドプロセスを開始したり、他の関数を呼び出したりするためにshow関数を使うことができないことを意味しています。全体から見ると、これは良いことです。通常のWebフレームワークが出来ないようなパフォーマンスや信頼性の保証を得ることをCouchDBに与えます。なぜならshow関数は、同じ入力に対して常に同じ結果を返します。そして、それが稼働する環境について何も変更することはできません。アウトプットはキャッシュされ、効率よく再利用されます。適切なキャッシングによる高可用性の実装において、これは与えられたshow関数が、個々のドキュメントに対して一度だけ呼ばれることを意味しており、CouchDBサーバは次のリクエストがきてもドキュメントには触れません。

Working without side effects can be a little bit disorienting for developers who are used to the anything-goes approach offered by most application servers. It’s considered best practice to ensure that actions run in response to GET requests are side effect–free and cacheable, but rarely do we have the discipline to achieve that goal. CouchDB takes a different tack: because it’s a database, not an application server, we think it’s more important to enforce best practices (and ensure that developers don’t write functions that adversely effect the database server) than offer absolute flexibility. Once you’re used to working within these constraints, they start to make a lot of sense. (There’s a reason they are considered best practices.)

副作用なしのshow関数の動作は、殆どのアプリケーションサーバによって提供される何でもありの方法を使っていた開発者にとって少し方向感を失わせてしまうかもしれません。これは副作用無く、キャッシュ可能なGETリクエストのためのレスポンスでの動作を確実に行うためのベストプラクティスであると考えられます。しかし、この目的を達成するために練習が必要になることはまれです。CouchDBは異なる方法を取ります。なぜならCouchDBはデータベースだからです。アプリケーションサーバではありません。ベストプラクティスを実施するため、無条件に柔軟性を提供するよりももっと重要なことを考えます。(そして、ディベロッパーがデータベースサーバに対して不利に影響するような関数を書かなくてよいようにします。)一度この制約に慣れれば、その理由に納得がいくでしょう。(それらがベストプラクティスであると考えられる理由があるわけです)

Design Documents

デザインドキュメント

Before we look into show functions themselves, we’ll quickly review how they are stored in design documents. CouchDB looks for show functions stored in a top-level field called shows, which is named like this to be parallel with views, lists, and filters. Here’s an example design document that defines two show functions:

show関数そのものを見る前に、デザインドキュメントにそれらがどのように保管されるかを再確認してみよう。CouchDBはトップレベルのshowsフィールド(viewslists, filtersと並列になるように配置されます)にshow関数が保管されているのを探します。以下は二つのshow関数が定義されたドキュメントの例です。

{
  "_id" : "_design/show-function-examples",
  "shows" : {
    "summary" : "function(doc, req){ ... }",
    "detail" : "function(doc, req){ ... }"
  }
}

There’s not much to note here except the fact that design documents can define multiple show functions. Now let’s see how these functions are run.

ここでは、デザインドキュメントの中に複数のshow関数が定義できるという事実以外の何も述べることはありません。さて、これらの関数がどのように動作するかみていきましょう。

Querying Show Functions

ショウ機能への問い合わせ

We’ve described the show function API, but we haven’t yet seen how these functions are run.

ここまでshow関数のAPIを述べました、しかしまだそれらの関数がどのように動作するかについては見ていません。

The show function lives inside a design document, so to invoke it we append the name of the function to the design document itself, and then the ID of the document we want to render:

show関数はデザインドキュメント内にあり、呼び出すために関数の名前をデザインドキュメントの中に記述します。そして表示したいドキュメントIDを以下のように指定します。

GET /mydb/_design/mydesign/_show/myshow/72d43a93eb74b5f2

Because show functions (and the others like list, etc.) are available as resources within the design document path, all resources provided by a particular design document can be found under a common root, which makes custom application proxying simpler. We’ll see an example of this in Part III, “Example Application”.

show関数(listのような他の関数なども)はデザインドキュメントのパスの中のリソースとして利用でき、個々のデザインドキュメントによって提供されるすべてのリソースがカスタムのアプリケーションプロキシを作るのと同じように共通のルート以下に見つけることができます。例をPart III, “Example Application”で見ることができます。

If the document with ID 72d43a93eb74b5f2 does not exist, the request will result in an HTTP 500 Internal Server Error response. This seems a little harsh; why does it happen? If we query a show function with a document ID that doesn’t point to an existing document, the doc argument in the function is null. Then the show function tries to access it, and the JavaScript interpreter doesn’t like that. So it bails out. To secure against these errors, or to handle non-existing documents in a custom way (e.g., a wiki could display a “create new page” page), you can wrap the code in our function with if(doc !== null) { ... }.

もし、ドキュメントIDが72d43a93eb74b5f2であるドキュメントが存在しない場合、リクエストはHTTP 500 Internal Server Errorとなります。これは、少し厳しすぎるように見えますが、なぜそうなるのでしょうか。もしshow関数に存在しないドキュメントのドキュメントIDを指定して要求した場合、関数内のdoc引数はnullになります。そして、show関数はそのドキュメントにアクセスしようとしますが、JavaScriptインタプリタは実行せずに、処理を抜け出します。これらのエラーや存在しないドキュメントをハンドルすること(例えば、wikiで"create new page"など存在しないページを表示する場合)を恐れないようにするため、関数の中のコードをif(doc!==null){ ... }で囲みます。

However, show functions can also be called without a document ID at all, like this:

しかしながら、show関数はドキュメントID無しでも呼び出すことができます。以下のように指定します。

GET /mydb/_design/mydesign/_show/myshow

In this case, the doc argument to the function has the value null. This option is useful in cases where the show function can make sense without a document. For instance, in the example application we’ll explore in Part III, “Example Application”, we use the same show function to provide for editing existing blog posts when a DocID is given, as well as for composing new blog posts when no DocID is given. The alternative would be to maintain an alternate resource (likely a static HTML attachment) with parallel functionality. As programmers, we strive not to repeat ourselves, which motivated us to give show functions the ability to run without a document ID.

この場合、関数へのdoc引数は nullになります。この選択はshow関数がドキュメント無しでも意味をなすことができる場合に便利です。例えば、Part III, “Example Application”で説明した例題のアプリケーションでは、DocIDが与えられない場合に新しいブログの投稿を構成するのと同様に、DocIDが与えられた場合に存在するブログの投稿の編集を行う方法としても同じshow関数を使います。代替手段としては替わりのリソース(静的なHTMLの添付のような)を別の機能として管理する方法です。プログラマとして、show関数がドキュメントID無しでも動作するように対応することで、同じことを繰り返さないように努めます。

Design Document Resources

デザインドキュメントリソース

In addition to the ability to run show functions, other resources are available within the design document path. This combination of features within the design document resource means that applications can be deployed without exposing the full CouchDB API to visitors, with only a simple proxy to rewrite the paths. We won’t go into full detail here, but the gist of it is that end users would run the previous query from a path like this:

show関数を実行するための機能に加えて、他のリソースがデザインドキュメントパスの中で利用可能です。これらのようなデザインドキュメントリソース内の機能の組み合わせは、パスを書き換えるための単純なプロキシを用いることで、アプリケーションが訪問者に対して完全なパスでのCouchDB APIを提供することなく、実装できることを意味しています。ここでは詳細については述べませんが、ここで言いたいことは、上で述べたようなパスへのアクセスを、ユーザは以下のようにアクセスできるだろうということです。

GET /_show/myshow/72d43a93eb74b5f2

Under the covers, an HTTP proxy can be programmed to prepend the database and design document portion of the path (in this case, /mydb/_design/mydesign) so that CouchDB sees the standard query. With such a system in place, end users can access the application only via functions defined on the design document, so developers can enforce constraints and prevent access to raw JSON document and view data. While it doesn’t provide 100% security, using custom rewrite rules is an effective way to control the access end users have to a CouchDB application. This technique has been used in production by a few websites at the time of this writing.

HTTPプロキシを使えば、標準的なクエリでみるデータベースやデザインドキュメントのパスの一部分(この場合は/mydb/_design/mydesign)をURLの前方に追加することができます。システムを適切に設定すれば、エンドユーザはデザインドキュメントに定義された関数を通してのみアプリケーションにアクセスできます。そしてディベロッパーはJSONドキュメントそのものやビューデータへの制約やアクセスを防ぐことができます。しかし、これは100%のセキュリティを提供するわけではありません。カスタムのrewrite ruleを使うことはCouchDBアプリケーションへのエンドユーザのアクセスを管理するための有効的な方法です。このやり方は現在いくつかのWebサイトで利用されている方法です。

Query Parameters

クエリパラメーター

The request object (including helpfully parsed versions of query parameters) is available to show functions as well. By way of illustration, here’s a show function that returns different data based on the URL query parameters:

リクエストオブジェクト(クエリパラメーターのバージョンの解析の手助けを含む)は同じようにshow関数で利用できます。実例としては、URLクエリパラメーターに元づいて異なるデータを返すようなshow関数は以下のようになります。

function(doc, req) {
  return "<p>Aye aye, " + req.parrot + "!</p>";
}

Requesting this function with a query parameter will result in the query parameter being used in the output:

クエリパラメーターを与えてこの関数を実行すると、以下のようにクエリパラメーターを結果の中に利用するような結果を得られます。

GET /mydb/_design/mydesign/_show/myshow?parrot=Captain

In this case, we’ll see the output: <p>Aye aye, Captain!</p>

上のようなケースの場合、アウトプットとしては<p>Aye aye, Captain!</p>のようなものを確認できます。

Allowing URL parameters into the function does not affect cacheability, as each unique invocation results in a distinct URL. However, making heavy use of this feature will lower your cache effectiveness. Query parameters like this are most useful for doing things like switching the mode or the format of the show function output. It’s recommended that you avoid using them for things like inserting custom content (such as requesting the user’s nickname) into the response, as that will mean each users’s data must be cached separately.

関数にURLパラメータを許可することでキャッシュが効かないということはありません。はっきりと異なるURLであればそれぞれ固有の結果となります。しかし、この機能の扱いを間違えるとキャッシュの効果を低下させてしまいます。このようなクエリパラメーターは、モードやshow関数の出力フォーマットを切り替えるような役割にもっとも役立ちます。レスポンスへカスタムされた内容(ユーザの名前を要求するような)を挿入するようなことへの利用は避けることを推奨します。これはそのデータが独立してキャッシュされなければならないようなデータであるためです。

Accept Headers

Part of the HTTP spec allows for clients to give hints to the server about which media types they are capable of accepting. At this time, the JavaScript query server shipped with CouchDB 0.10.0 contains helpers for working with Accept headers. However, web browser support for Accept headers is very poor, which has prompted frameworks such as Ruby on Rails to remove their support for them. CouchDB may or may not follow suit here, but the fact remains that you are discouraged from relying on Accept headers for applications that will be accessed via web browsers.

HTTPの使用の一部では、サーバがどのようなメディアタイプを受け入れてくれるかを確認するための方法をクライアントに許可しています。CouchDB 0.10.0のJavaScriptクエリサーバはAccept Headerを処理するための機能を持っています。しかし、サポートを削除するためにRuby on Railsのような有名なフレームワークを使うほど、WebブラウザのAccept Headerに対するサポートはとても乏しいものです。

There is a suite of helpers for Accept headers present that allow you to specify the format in a query parameter as well. For instance:

現在Accept headersを助けるような機能があり、クエリパラメーターにフォーマットを指定することが可能です。例えば、以下は間違ったAccept HeaderでURLにアクセスしたような時と同じです。

GET /db/_design/app/_show/post
Accept: application/xml

is equivalent to a similar URL with mismatched Accept headers. This is because browsers don’t use sensible Accept headers for feed URLs. Browsers 1, Accept headers 0. Yay browsers.

これは、ブラウザがフィードに適したAccept headerを扱えないためです。

GET /db/_design/app/_show/post?format=xml
Accept: x-foo/whatever

The request function allows developers to switch response Content-Types based on the client’s request. The next example adds the ability to return either HTML, XML, or a developer-designated media type: x-foo/whatever.

リクエスト関数は、開発者がクライアントのリクエストに応じてレスポンスのContent-Typeを変更できるようにします。次の例では、HTMLやXMLまたは開発者が独自に作ったx-foo/whateverタイプを返す機能を追加しています。

CouchDB’s main.js library provides the ("format", render_function) function, which makes it easy for developers to handle client requests for multiple MIME types in one form function.

CouchDBのmain.jsライブラリは("format", render_function) 関数を提供しており、一つの関数でクライアントがリクエストしてくる複数のMIME typeに簡単に対応できるようにします。

This function also shows off the use of registerType(name, mime_types), which adds new types to mapping objects used by respondWith. The end result is ultimate flexibility for developers, with an easy interface for handling different types of requests. main.js uses a JavaScript port of Mimeparse, an open source reference implementation, to provide this service.

この関数はまた、respondWithを使うことで新しいタイプをマッピングオブジェクトに追加するための、registerType(name, mime_types)の利用を見せるためでもあります。結果的には、複数の異なるタイプを処理するための簡単なインタフェースによって開発者への最高の柔軟性をもたらします。main.jsMimeparseのJavaScript portを使います。それはこのサービスを提供するための、オープンソースの参照実装です。

Etags

We’ve mentioned that show function requests are side effect–free and cacheable, but we haven’t discussed the mechanism used to accomplish this. Etags are a standard HTTP mechanism for indicating whether a cached copy of an HTTP response is still current. Essentially, when the client makes its first request to a resource, the response is accompanied by an Etag, which is an opaque string token unique to the version of the resource requested. The second time the client makes a request against the same resource, it sends along the original Etag with the request. If the server determines that the Etag still matches the resource, it can avoid sending the full response, instead replying with a message that essentially says, “You have the latest version already.”

show関数のリクエストは副作用がなくキャッシュ可能であることを述べました。しかし、これを成し遂げるための仕組みについてはまだ議論していません。Etagsは、HTTPレスポンスのキャッシュされたコピーがまだ正しい情報であるかどうかを示すための標準的なHTTPの仕組みです。本質的に、クライアントはリソースに初めてのリクエストを行うとき、レスポンスにはEtagが付いてきます。Etagは要求されたリクエストのバージョンを示す難解な文字列トークンです。クライアントが同じリソースに対するリクエストを再度行うと、リクエストは最初のEtagを送ります。もしサーバがリクエストのEtagがリソースに合致していると判断したとき、完全なレスポンスを送ることを避けることができ、"既に最新のバージョンのレスポンスをもっています"という意味のメッセージを返さずにすみます。

When implemented properly, the use of Etags can cut down significantly on server load. CouchDB provides an Etag header, so that by using an HTTP proxy cache like Squid, you’ll instantly remove load from CouchDB.

適切に実装されていれば、Etagの使用はサーバ負荷を大きく下げることができます。CouchDBはEtagヘッダを提供しており、SquidのようなHTTP proxyキャッシュを使うことで、簡単にCouchDBからのロードを減らせます。

Functions and Templates

関数とテンプレート

CouchDB’s process runner looks only at the functions stored under show, but we’ll want to keep the template HTML separate from the content negotiation logic. The couchapp script handles this for us, using the !code and !json handlers.

CouchDBのプロセスはshowとして保管された関数だけを見ています。しかし、私たちは内容の処理ロジックとHTMLテンプレートを分けて保管したいと考えます。couchappスクリプトは、!codeと!jsonハンドラを使うことで、これを扱います。

Let’s follow the show function logic through the files that Sofa splits it into. Here’s Sofa’s edit show function:

SofaでロジックとHTMLテンプレートを分けているファイルを参考に、show関数の処理について理解しましょう。以下はSofaのedit show関数です。

function(doc, req) {
  // !json templates.edit
  // !json blog
  // !code vendor/couchapp/path.js
  // !code vendor/couchapp/template.js

  // we only show html
  return template(templates.edit, {
    doc : doc,
    docid : toJSON((doc && doc._id) || null),
    blog : blog,
    assets : assetPath(),
    index : listPath('index','recent-posts',{descending:true,limit:8})
  });
}

This should look pretty straightforward. First, we have the function’s head, or signature, that tells us we are dealing with a function that takes two arguments: doc and req.

これはとても単純な例です。まず、関数のヘッダ署名があります。そして、二つの引数doc, reqを取る関数を扱っていることを示しています。

The next four lines are comments, as far as JavaScript is concerned. But these are special documents. The CouchApp upload script knows how to read these special comments on top of the show function. They include macros; a macro starts with a bang (!) and a name. Currently, CouchApp supports the two macros !json and !code.

JavaScriptから考えると、始めの4行はコメントです。しかし、特殊なドキュメントです。CouchAppのアップロードスクリプトはどのようにshow関数の上の方にある特殊なコメントを読み取ればよいかを知っています。それらはマクロを含みます。マクロはエクスクラメーションマーク(!)から始まる名前になります。今のところCouchAppは二つのマクロ!json!codeをサポートしています。

The !json Macro

The !json macro takes one argument: the path to a file in the CouchApp directory hierarchy in the dot notation. Instead of a slash (/) or backslash (\), you use a dot (.). The !json macro then reads the contents of the file and puts them into a variable that has the same name as the file’s path in dot notation.

!jsonマクロは一つの引数を取ります。ドット表記で表したCouchAppディレクトリ階層でのファイルへのパスを渡します。スラッシュ(/)やバックスラッシュ(\)のかわりに、ドット(.)を使います。!jsonマクロはファイルの内容を、ドット表記で書かれたファイルのパスと同じ名前の変数に読み込みます。

For example, if you use the macro like this:

例えば、もし以下のようなマクロを使う場合なら、

  // !json template.edit

CouchDB will read the file template/edit.* and place its contents into a variable:

CouchDBはtmeplate/edit.*ファイルを読み込み、以下のように変数に内容を置き換えます。

  var template.edit = "contents of edit.*"

When specifying the path, you omit the file’s extension. That way you can read .json, .js, or .html files, or any other files into variables in your functions. Because the macro matches files with any extensions, you can’t have two files with the same name but different extensions.

パスを指定するとき、ファイルの拡張子を取り除きます。それにより、.json, .js, .htmlといったファイルや、その他のファイルを関数内の変数として読み込むことができます。マクロはどのような拡張子のファイルにもマッチします。よって異なる拡張子で同じ名前の二つのファイルを持つことはできません。

In addition, you can specify a directory and CouchApp will load all the files in this directory and any subdirectory. So this:

加えて、ディレクトリを指定することができます。その場合、CouchAppはこのディレクトリやサブディレクトリ内のすべてのファイルを読み込みます。例えば以下のようになります。

  // !json template

creates:

と指定すると、

  var template.edit = "contents of edit.*"
  var teplate.post = "contents of post.*"

Note that the macro also takes care of creating the top-level template variable. We just omitted that here for brevity. The !json macro will generate only valid JavaScript.

留意するべきことは、マクロはトップレベルのtemplate変数を扱うことです。簡潔に示すためにここでは避けます。!jsonマクロは有効なJavaScriptだけを生成します。

The !code Macro

The !code macro is similar to the !json macro, but it serves a slightly different purpose. Instead of making the contents of one or more files available as variables in your functions, it replaces itself with the contents of the file referenced in the argument to the macro.

!codeマクロは!jsonマクロに似ています。しかし、若干目的が異なっています。関数の中の変数として一つまたはそれ以上のファイルの内容を作成する変わりに、マクロに指定した引数で参照されるファイルの内容をそのまま置き換えます。

This is useful for sharing library functions between CouchDB functions (map/reduce/show/list/validate) without having to maintain their source code in multiple places.

これは、CouchDB関数(map/reduce/show/list/validate)内の複数の場所でソースコードを管理することを避け、ライブラリ関数を共有するのに役立ちます。

Our example shows this line:

私たちの先ほどの例では、以下の行の部分です。

  // !code vendor/couchapp/path.js

If you look at the CouchApp sources, there is a file in vendor/couchapp/path.js that includes a bunch of useful function related to the URL path of a request. In the example just shown, CouchApp will replace the line with the contents of path.js, making the functions locally available to the show function.

CouchAppソースを確認する場合、vendor/couchapp/path.jsにファイルがあり、リクエストのURLパスに関する便利な関数がまとめられています。先ほどの例では、CouchAppはpath.jsの内容を置き換え、show関数内で利用できる関数を作ります。

The !code macro can load only a single file at a time.

!codeマクロは一度に一つのファイルだけ読み込めます。

Learning Shows

Showsを学ぶ

Before we dig into the full code that will render the post permalink pages, let’s look at some Hello World form examples. The first one shows just the function arguments and the simplest possible return value. See Figure 1, “Basic form function”.

投稿したパーマリンクのページを表示する完全なコードについて掘り下げていく前に、いくつかのHello Worldの例を見てみましょう。まず一つ目は、関数の引数を受け取り、最も単純な戻り値とする例です。Figure 1, “Basic form function”を見て下さい。

Figure 1. Basic form function

A show function is a JavaScript function that converts a document and some details about the HTTP request into an HTTP response. Typically it will be used to construct HTML, but it is also capable of returning Atom feeds, images, or even just filtered JSON. The document argument is just like the documents passed to map functions.

show関数はドキュメントとHTTPリクエストに関する詳細をHTTPリクエストに変換するJavaScript関数です。典型的にはHTMLの構造で使われますが、Atomフィードやイメージ、フィルタされたJSONなどで返すことも可能です。ドキュメント引数はmap関数へ渡されるドキュメントと似ています。

Using Templates

テンプレートを使う

The only thing missing from the show function development experience is the ability to render HTML without ruining your eyes looking at a whole lot of string manipulation, among other unpleasantries. Most programming environments solve this problem with templates; for example, documents that look like HTML but have portions of their content filled out dynamically.

show関数の開発をする上で欠けている一つのことは、多くの文字列操作やその他の不可解なことなどを見て目を痛めないように、HTMLを表示するための能力です。殆どのプログラミング環境はテンプレートでこの問題を解決します。例えば、HTMLのようなドキュメントに見えて、内容の一部を動的に埋め込みます。

Dynamically combining template strings and data in JavaScript is a solved problem. However, it hasn’t caught on, partly because JavaScript doesn’t have very good support for multi-line “heredoc” strings. After all, once you get through escaping quotes and leaving out newlines, it’s not much fun to edit HTML templates inlined into JavaScript code. We’d much rather keep our templates in separate files, where we can avoid all the escaping work, and they can be syntax-highlighted by our editor.

テンプレートの文字列とJavaScript内のデータを動的に結合することで問題が解決されます。しかし、JavaScriptは"ヒアドキュメント"のような複数行に対するとてもよいサポートがないため、あまり受け入れられません。結局のところ、一度エスケープクオートを通過したら改行を読み飛ばします。それはJavaScriptコードにインラインで使うようなHTMLテンプレートを編集するには好ましくありません。エスケープをすることを避けることができるようにファイルを分割して、エディタでシンタックスがハイライトされるようにテンプレートを管理したいです。

The couchapp script has a couple of helpers to make working with templates and library code stored in design documents less painful. In the function shown in Figure 2, “The blog post template”, we use them to load a blog post template, as well as the JavaScript function responsible for rendering it.

couchappスクリプトは苦痛を伴うこと無くデザインドキュメントにテンプレートやライブラリコードを記述するための二つの方法を提供します。 Figure 2, “The blog post template”に記載されている関数では、JavaScript関数がそれを表示するのと同じように、ブログ投稿のテンプレートを読み込むために使っています。

Figure 2. The blog post template

As you can see, we take the opportunity in the function to strip JavaScript tags from the form post. That regular expression is not secure, and the blogging application is meant to be written to only by its owners, so we should probably drop the regular expression and simplify the function to avoid transforming the document, instead passing it directly to the template. Or we should port a known-good sanitization routine from another language and provide it in the templates library.

ご覧のように、投稿フォームからJavaScriptタグを取り除くために関数を利用しています。その正規表現は安全ではありません。そしてブログアプリケーションは所有者によってだけ書かれることが望まれます。よって、テンプレートに直接データを渡す代わりに、おそらく正規表現をやめて、ドキュメントの転送を避けるための関数を簡略化するべきなのでしょう。もしくは、有名なサニタイズの方法を他の言語から移植するか、テンプレートライブラリを提供するのが良さそうです。

Writing Templates

テンプレートを書く

Working with templates, instead of trying to cram all the presentation into one file, makes editing forms a little more relaxing. The templates are stored in their own file, so you don’t have to worry about JavaScript or JSON encoding, and your text editor can highlight the template’s HTML syntax. CouchDB’s JavaScript query server includes the E4X extensions for JavaScript, which can be helpful for XML templates but do not work well for HTML. We’ll explore E4X templates in Chapter 14, Viewing Lists of Blog Posts when we cover forms for views, which makes providing an Atom feed of view results easy and memory efficient.

一つのファイルにすべての表現を詰め込むように調整するよりも、テンプレートを使うことで、もっとリラックスしてフォームを編集できるでしょう。テンプレートはテンプレートファイルそのものに保管されるため、JavaScriptやJSONエンコードについて心配する必要はありません。また、テキストエディタはテンプレートのHTMLシンタックスをハイライトできます。CouchDBのJavaScriptクエリサーバはJavaScriptのためのE4X拡張機能をもっており、XMLテンプレートに役立ちます。ただしHTMLにはうまく動作しません。ビューの結果としてAtomフィードを簡単胃提供したり、メモリ効率化を提供するビューの形を取り上げているChapter 14, Viewing Lists of Blog PostsでE4Xテンプレートについて探ります。

Trust us when we say that looking at this HTML page is much more relaxing than trying to understand what a raw JavaScript one is trying to do. The template library we’re using in the example blog is by John Resig and was chosen for simplicity. It could easily be replaced by one of many other options, such as the Django template language, available in JavaScript.

このHTMLページを見ることが、素のJavaScriptで出力することに挑戦し何かを理解しようとするよりも、もっと気楽になるということについて信じてください。ブログの例で私たちが使うテンプレートライブラリは、John Resigによって作られ単純化のために選択されています。JavaScriptで有効であるDjangoテンプレート言語のような沢山のオプションの一つによって簡単に置き換えることができます。

This is a good time to note that CouchDB’s architecture is designed to make it simple to swap out languages for the query servers. With a query server written in Lisp, Python, or Ruby (or any language that supports JSON and stdio), you could have an even wider variety of templating options. However, the CouchDB team recommends sticking with JavaScript as it provides the highest level of support and interoperability, though other options are available.

これはCouchDBのアーキテクチャがクエリサーバの言語を簡単に取り替えられるように設計されていることを知ってもらうためのよい機会です。Lisp, Python, Ruby (または他のJSONやstdinをサポートする言語)によって書かれたクエリサーバによって、公平に広く多様なテンプレートの選択肢を得ることができます。しかし、CouchDBチームは、他の選択肢が 利用可能であることを通して、サポートや下位互換性の高いレベルサポートを提供するためJavaScriptを利用し続けることを推奨します。