Realm Node.jsとExpressでブログを作成

11月16日にRealm Node.js版がリリースされました。Realmの強力な機能をサーバーサイドで使用できるようになります。Node.jsでRealmを活用する方法を示すために、簡単なブログを作成してみましょう。

このチュートリアルでは、コマンドラインはOS XやLinuxを前提としています。また、Node.jsとnpmがインストールされている必要があるので、インストールされていない場合、Node.jsサイトを参照してインストールしてください。

セットアップ

realm-blogというディレクトリで作業します。

mkdir realm-blog
cd realm-blog

まず、Node.jsプロジェクトを初期化するために、 npm initコマンドを実行します。

npm init

コマンドを実行すると以下のようにいくつかの項目の入力を求められます。version0.1.0に変え、descriptionをRealm Blogとしています。その他の項目は、デフォルト値に設定しました。

name: (realm-blog)
version: (1.0.0) 0.1.0
description: Realm Blog
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)

Webのリクエストを処理するためにExpress、データベースにRealm Node.js、テンプレート処理のためにEmbedded JavaScript(EJS)、フォームから渡されたクエリを処理するためにbody-parserを使用します。

記事の更新情報を受け取る

npm install --save express
npm install --save realm
npm install --save ejs
npm install --save body-parser

以降、コードを変更するたびにサーバーが再起動されるようにするためNodemonをインストールします。

npm install --save-dev nodemon

このままの状態でNodemonを使用してサーバーを実行するには、 ./node_modules/nodemon/bin/nodemon.js index.jsとする必要があります。これは、少し煩雑なので、package.jsonの中の"script" プロパティを以下のように書き換えてください、

{
  ...
  "scripts": {
    "serve": "nodemon index.js"
  },
  ...
}

これで、npm run serveとするだけでテストサーバーを実行できます。

Hello Realm!

まず、/リクエストを処理するコードを登録しましょう。index.jsを作成し、以下のように入力してください。

'use strict';

var express = require('express');

var app = express();

app.get('/', function(req, res) {
  res.send("Hello Realm");
});

app.listen(3000, function() {
  console.log("Go!");
});

/アドレスに GET要求が来る簡単に画面にHello Realmと表示し、 3000番ポートを介して行わがされます。 Webブラウザで localhost:3000を開いてみましょう。npm run serveの実行をわすれないでください。

hello-realm

書き込み機能の実装

それでは次にエントリを書く機能を実装してみましょう。まず、書き込みフォームを作ります。write.htmlファイルを次のように作成します。

<form action="/write" method="POST">
  <input type="text" name="title" /><br />
  <textarea name="content"></textarea><br />
  <button type="submit">Submit</button>
</form>

/writeアドレスに届くGETリクエストを処理するために、index.jsapp.listenの行の前に次のコードを追加します。

app.get('/write', function(req, res) {
  res.sendFile(__dirname + "/write.html");
});

/writeに対して、現在のディレクトリのwrite.htmlファイルを出力します。

Webブラウザで localhost:3000/writeにアクセスしてみましょう。

write

エントリをsubmitすると、 /writeアドレスにPOSTリクエストがくるので、これを処理するためのコードを追加します。index.jsにパーサーを追加します。

var express = require('express'),
    bodyParser = require('body-parser');

var app = express();

app.use(bodyParser.urlencoded({extended: true}));

app.post('/write', function(req, res) {
  res.send(req.body);
});

localhost:3000/writeに接続して何かに入力してみましょう。 submitを押すとPOSTリクエストが発行され、webブラウザに次のように出力されます。

{"title":"nice","content":"to meet you"}

Realmスキーマの作成

Realm Node.jsでスキーマを作りましょう。index.jsをひらき、中身を以下のように書き換えます。

'use strict';

var express = require('express'),
  bodyParser = require('body-parser'),
  Realm = require('realm');

var app = express();
app.use(bodyParser.urlencoded({extended: true}));

let PostSchema = {
  name: 'Post',
  properties: {
    timestamp: 'date',
    title: 'string',
    content: 'string'
  }
};

var blogRealm = new Realm({
  path: 'blog.realm',
  schema: [PostSchema]
});

app.get('/', function(req, res) {
  res.send("Hello Realm");
});

app.get('/write', function(req, res) {
  res.sendFile(__dirname + "/write.html");
});

app.post('/write', function(req, res) {
  res.send(req.body);
});

app.listen(3000, function() {
  console.log("Go!");
});

注目すべき部分が2つあります。まず、 PostSchemaを作成している部分です。PostSchemaには2つの属性があり、一つは、モデルの名前であるname属性で、値はPostとしています。もう一つはこのPostモデルの各種情報を保持するproperties属性で、その中には3つの属性 timestamptitle contentを宣言しています。

このように作成されたスキーマを、Realmのインスタンスを作成するときに、コンストラクタに渡します。 path属性は、データベースファイル名です。schema属性は データベースファイル中で使用するモデル定義を配列で指定します。今回はPostモデルのみなので[PostSchema]としています。複数のモデルを登録する場合には、配列に要素を追加してください。

Realmでデータの書き込み

エントリを作成するために /writeアドレスの POSTハンドラを以下のように変更しましょう。

app.post('/write', function(req, res) {
  let title = req.body['title'],
    content = req.body['content'],
    timestamp = new Date();
  blogRealm.write(() => {
    blogRealm.create('Post', {title: title, content: content, timestamp: timestamp});
  });
  res.sendFile(__dirname + "/write-complete.html");
});

Realmインスタンスに対して writeメソッドで書き込みトランザクションを開き、createメソッドで実際の書き込みを行っています。書き込み後の画面のため、write-complete.htmlを、次のように作成しておきましょう。

<a href="/">Success!</a>

作成されたエントリを表示する

それではメイン画面で、作成されたエントリを読み出して出力しましょう。

viewsディレクトリにindex.ejsを作成します。

<h2>Realm Blog</h2>

<a href="/write">Write</a>

<% for(var i=0; i<posts.length; i++) {%>
<h3><%= posts[i].title%></h3>
<p><%= posts[i].content%></p>
<% } %>

これは、 postsに渡されたブログのポストを出力するテンプレートです。

テンプレートにpostsを渡すよう変更されたハンドラは以下の通りです。

app.set('view engine', 'ejs');

app.get('/', function(req, res) {
  let posts = blogRealm.objects('Post').sorted('timestamp', true);
  res.render('index.ejs', {posts: posts});
});

app.setでテンプレートエンジンとしてEmbedded Javascript(EJS)を使用することを宣言します。Postオブジェクトをすべて取得し、timestampeの値の降順に(sortedの二番目の引き数がreverseオプションです。省略すると、昇順)並べ替えます。

実行して /writeを介してエントリを作成してみると以下のような画面が表示されます。

complete

最終的なコードはこちらで確認することができます。

About the content

This content has been published here with the express permission of the author.


Leonardo YongUk Kim

Leonardo YongUk Kim is a software developer with extensive experience in mobile and embedded projects, including: several WIPI modules (Korean mobile platform based on Nucleus RTOS), iOS projects, a scene graph engine for Android, an Android tablet, a client utility for black boxes, and some mini games using Cocos2d-x.

山﨑 誠

Makoto Yamazaki is a software engineer with extensive experience in Java and Android. He is a member of Realm Java team and also CTO of uPhyca Inc.

4 design patterns for a RESTless mobile integration »

close