Realm Node.js와 Express로 블로그 만들기

Realm의 Node.js 버전이 11월 16일에 출시되었습니다. Realm의 강력한 기능을 이제 서버 사이드에서 Node.js로 사용할 수 있게 되었습니다. Node.js에서 Realm을 활용하는 법을 보여주기 위해 간단한 블로그를 만들어 보겠습니다.

이 튜토리얼은 사용자가 셸 환경을 사용할 수 있는 macOS나 리눅스 환경을 사용할 수 있다고 가정하고 있고 Node.js와 npm이 설치되어 있다고 가정하고 있습니다. 설치되어 있지 않다면 Node.js 사이트를 참고하여 설치하세요.

기본 환경 설정하기

realm-blog 라는 디렉터리에서 시작하겠습니다.

mkdir realm-blog
cd realm-blog

먼저 Node.js 프로젝트를 초기화하기 위해 npm init 명령을 이용합니다.

$npm init
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)

이후 물어보는 항목은 적절히 채웠습니다. name 항목은 디렉터리 명으로 지정되는데 그대로 두었고 버전은 1.0.0으로 하기에 민망한 수준이기 때문에 0.1.0으로 바꾸었습니다. 다른 항목들은 다 기본값으로 설정하였습니다.

웹 요청을 처리하기 위해 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번 포트를 통해 수행됩니다. npm run serve로 서버를 시작하고 웹 브라우저에서 localhost:3000을 열어볼까요?

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 파일을 화면에 출력합니다.

웹 브라우저에서 localhost:3000/write 요청을 해봅시다.

write

글을 작성하면 /write 주소로 POST 요청이 오는데 이를 처리하기 위해 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에 접속하여 아무렇게나 입력해 봅시다. POST 요청에 대해 다음과 같이 출력되는 것을 볼 수 있습니다.

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

Realm 스키마 만들기

Realm Node.js에 스키마를 만듭니다. 스키마를 추가한 전체 코드는 아래와 같습니다.

'use strict';

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

var app = express();

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

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

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

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!");
});

크게 주목해야 할 부분은 두 가지 부분입니다. 먼저 PostSchema를 만들었습니다. 여기에 두 속성이 있는데 하나는 모델의 이름인 name이며 처음 만든 모델의 이름은 Post로 지정하였습니다. 그 안에 들어갈 속성은 properties에 넣는데 3가지 속성 timestamp, title, 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

전체 예제는 여기에서 확인할 수 있습니다.

컨텐츠에 대하여

이 컨텐츠는 저자의 허가 하에 이곳에서 공유합니다.


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

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