search
LoginSignup
7
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

vte.cx Advent Calendar 2016 Day 9

posted at

updated at

サーバサイドJavaScriptの実装例と単体テスト

先日、フロントエンドが主導してAPIのI/Fを決定していく開発の話をしました。
このあたりは実際のコードがないとイメージしずらいでしょう。

この記事は古いので、こちらを参照してください。


今日はvte.cxにおけるサーバサイドのサービス実装方法についてサンプルを交えて説明したいと思います。サンプルコードは、vtecxblankに置いています。
動かし方は、React+vte.cxで業務アプリを作る #1(環境設定〜動作確認まで)を参考にしてください。

サーバサイドJavaScriptの基本

基本的なところについては、まず、【vte.cx応用】20.サーバーサイドJavascriptについてに目を通してください。
注) 2017/7 webpack対応に伴い、module.exportsで括らなくてもいいようにしました。従来の方法で使いたい場合は、/_settings/propertiesのrightsに、use_webpack=falseを設定してください。

この例にあるように、getfeed.jsを/serverフォルダに置いてデプロイし、/s/getfeedにアクセスするとサーバサイドで実行されて/registrationの配下の内容がFeedで返ります。簡単ですね。
また、reflexcontextのAPIについては、ドキュメントを参照してください。

server/getfeed.js
import reflexcontext from 'reflexcontext' 

const feed = reflexcontext.getFeed('/registration')
reflexcontext.doResponse(feed) 

複数クラスのサンプル

ただ、上記の例は1つのファイルしかありません。
単純なものであればそれいいのですが大規模になってくると困ります。通常は複数のクラスにわけて実装すべきでしょう。

vte.cxでは、webpackにより様々なモジュールをバンドルすることが可能です。
例えば、以下のように、index.jsからPersonクラスをimportして、person.say()メソッドを呼ぶことができます。

app/server/index.js
import reflexcontext from 'reflexcontext' 
import Person from './person'

const person = new Person('Steve')
reflexcontext.log(person.say())
reflexcontext.sendMessage(200, person.say())
app/server/person.js
/* @flow */
export default class Person {
    name:string
    constructor(
        name:string = 'dummy'
    ) {
        this.name = name
    }

    say():string {
        return 'Hello, I\'m ' + this.name + '!!'
    }
}

また、サーバログにも同じ内容が書き込まれています。
ブラウザからhttps://{サービス名}.1.vte.cx/d/_log?x&fを指定して確認してみましょう。ログの内容がXMLで表示されたかと思います。

サーバサイドレンダリング

Reactの機能を使うことでSSR(サーバサイドレンダリング)を実行できます。
/s/ssr.htmlにアクセスすると、「Hello, World」が表示されます。

ssr.html.js
import reflexcontext from 'reflexcontext' 
import React from 'react'
import ReactDOMServer from 'react-dom/server'

const element = (
        <h3> Hello, World! </h3> 
)

const html = ReactDOMServer.renderToStaticMarkup(element)

reflexcontext.doResponseHtml(html)

SSRによるPDFの出力

さらに、SSRの機能を使ってPDFを出力できます。
PDF出力機能のテンプレートにSSRで生成したHTMLを指定するとダイナミックにPDFを生成できるようになります。
以下のサンプルでは、/s/ssr.pdfにアクセスするとPDFを動的に生成しダウンロードします。

ssr.pdf.js
import reflexcontext from 'reflexcontext' 
import React from 'react'
import ReactDOMServer from 'react-dom/server'

function formatName(user) {
    return user.firstName + ' ' + user.lastName
}

const user = {
    firstName: 'Harper',
    lastName: 'Perez'
}

const element = (
    <html>
        <body>
            <div className="_page" style={{ pagesize: 'A4', orientation: 'portrait'}}>
                <table>
                    <tr>
                        <td>
                            <p> Hello, {formatName(user)}! </p> 
                        </td>
                    </tr>
                </table>
            </div>
        </body>
    </html>
)

const html = ReactDOMServer.renderToStaticMarkup(element)

// PDF出力
reflexcontext.toPdf({}, html, 'test.pdf')

Mochaによる単体テスト

複数のクラスに分割できると単体テストもやりやすくなります。
以下にその方法について説明します。

まず、mochaとES6で書かれたコードをテストするespower-babelを入れます。

sudo npm install -g mocha
npm install --save-dev mocha
npm install --save-dev should
npm install --save-dev espower-babel

以下はserver/person.jsをテストするコードです。

test/test_person.js
import should from 'should'
import Person from '../src/server/person'

let person

before(function(){
    person = new Person('Steve')
})

describe('Person', function(){
    it('person.say() is OK', function(){
        person.say().should.exactly('Hello, I\'m Steve!!')
    })
})

以下のように実行するとサービスの実行結果が表示されます。

$ mocha --compilers js:espower-babel/guess test/test_person.js

  Person
    ✓ person.say() is OK


  1 passing (12ms)

それでは、また。:relaxed:

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
7
Help us understand the problem. What are the problem?