astamuse Lab

astamuse Labとは、アスタミューゼのエンジニアとデザイナーのブログです。アスタミューゼの事業・サービスを支えている知識と舞台裏の今を発信しています。

はじめてのExpress.js 〜導入編〜

こんにちは。デザイン部でフロントエンドエンジニアをしているkitoです。
今回から数回に渡って、Node.jsのWebフレームワークExpress.jsのご紹介をしていきたいと思います。

はじめに

数多く存在するのWebフレームワークのなかから、Node.jsのフレームワークを導入する理由をあげるとすれば何があるでしょうか? 有力な理由のひとつは、PayPal社の事例 でもわかるように、共通のプログラミング言語、つまりJavaScriptをブラウザ側とサーバ側両方で活用することで、フロントエンドとバックエンドの垣根を取り払い、ひとつのチームで両方の問題に素早く対応できるようにすることがあげられます。これは「Isomorphic」あるいは最近では「Universal」なアプリケーションと呼ばれています。

もちろん、Universalなアプリケーションが常プラスに働くとは限りません。ひとつのチームではなく複数チームにタスクを分担することで開発効率をあげるやり方(基本的に弊社もこの方式です)は、スケールしやすく複雑な問題に対応できます。とはいえ、Universalなアプリケーションなら、開発、運用、改善のサイクルを迅速に回すことができ、それによってアプリケーションの質を高めつつ柔軟に外部環境の変化に対応できます。身軽なWebアプリケーション開発と運用に最優先にするなら、Node.jsのフレームワークを選択することは、適材適所という意味で理にかなっているでしょう。
本稿では、Node.jsのフレームワークのなかでもデファクトスタンダードなExpress.jsを詳しく説明していきますが、もうひとつの有力フレームワークであるSails.jsと比較してみると、Express.jsの輪郭を把握しやすくなるでしょう。

Express.jsの特長

Express.jsは軽量でシンプルなマイクロフレームワークです。 公式サイトでは『特定の意見に固執しない、Node.js向けの高速で最小限のWebフレームワーク』と謳われています。Rubyのフレームワークで例えるなら、Sinatraに似ています。 公式サイト

Sails.jsの特長

Sails.jsはExpress.jsをベースにつくられています。Express.jsがSinatraライクなフレームワークであるとするなら、Sails.jsは名前からもわかる通りRuby and Railsライクな比較的重量級のフレームワークです。Railsよろしくsails generateコマンドでmodelやcontrollerを作成できます。RESTfulなJSON APIが自動生成されるのでデータドリブンなアプリケーションに向いています。また、WaterlineというORMを備えています。 公式サイト

Sails.jsを仮に導入するとしても、その元になっているExpress.jsを学んでおいた方が理解が早まるでしょう。またSails.jsのWaterlineはモジュール化されているのでExpress.jsでも利用できます。

Node.jsのインストール

Express.jsをインストールするには、Node.jsが必須です。Node.jsをインストールされていない方はインストールしましょう。 Node.jsの公式サイトからインストールできます。 Macを使われていてHomebrewを導入済みなら、以下のコマンドをターミナルで実行してインストールできます。

brew install node

インストールできたらバージョンを確認してみましょう。 Windowsならコマンドプロンプト、Macならターミナルから以下を実行します。

node -v

本稿では、最新バージョンであるv6.2.0を前提にして進めます。

Node.jsをインストールできたので、同時にnpmというパッケージ管理システムがインストールされました。 npmを使ってExpress.jsをインストールできるようになりましたが、ここでnpmについて説明します。

npm

npmはNode Package Managerの略で、Nodeモジュールを管理するツールです。Express.jsもこのNodeモジュールとして提供されているので、Express.jsを使う場合は、事実上は必須のツールと考えてよいでしょう。もっとも、利用するのにそれほど複雑なツールではありません。幾つかのコマンドを覚えれば迷わず使うことができるでしょう。 まず、myappというディレクトリを作成してnpmを初期化します。

mkdir myapp && cd myapp
npm init

上記をターミナルorコマンドプロンプト実行すると、インタラクティブにnameやdescriptionなどが聞かれます。後から修正できるのでまずはすべてEnterキーで良いでしょう。するとmyapp内にpackage.jsonというファイルが作成されます。ここにはモジュールの名前や依存関係が記述されていきます。 では、早速express.jsをnpmでインストールしてみましょう。 以下を実行すると、しばらく時間がかかりますがインストールできます。

npm install express --save

--saveは、npmのオプションのひとつで、これをつけてインストールするとpackage.jsonのdependenciesに依存関係が記述されます。また、--save-devオプションをつけると、devDependencieに依存関係が記述されます。

その他、よく使うnpmコマンドは以下のようなものがあります。 npmモジュールをグローバル領域にインストールする際に使います。

npm install -g モジュール名

installはiにた短縮可能です。

npm i モジュール名

モジュール名@バージョンで任意バージョンのインストールができます。

npm install express@4.13.4

モジュール名 -Vでインストールされているバーションを確認できます。

express -V
4.13.1

バージョンを確認できれば、express.jsがインストールされたことが確認できます。

Node.jsでつくるアプリケーション

Express.jsを動かしてみる前に、回り道のようですがExpress.jsを使わずにNode.jsだけ簡易なHTTPサーバーを作成してみましょう。 任意のフォルダを作成してください。その中にserver.jsというファイルを作成して、以下のコードを記述してください。

var http = require('http');

var server = http.createServer(function(req, res) {
   res.writeHead(200, {'Content-Type': 'text/plain'});
   res.write('Hello World!');
   res.end();
});

server.listen(3000, function () {
  console.log('listening on port 3000');
});

上記コードを説明します。
var http = require('http')でhttpモジュールを読み込み、HTTPサーバーのオブジェクトを作成しています。
httpモジュールはNode.jsのコアモジュールなので、Node.jsと一緒にインストールされています。改めてnpmでインストールする必要はありません。 そして、httpモジュールのcreateServerメソッドを使ってサーバーのを作成します。 引数のreqとresには、それぞれリクエストオブジェクトとレスポンスオブジェクトが渡さるので、コールバック関数に、リクエストがあるたびに呼ばれる処理を書いていきます。 res.writeHeadでステータスコードとHTTPレスポンスヘッダーを送信し、同様にres.writeでレスポンスの本体を送信します。res.endでレスポンスを終了します。 server.listenでは、リクエストの着信を待ち受け状態にしています。第1引数は待受けているportの番号を渡しています。

これを実行しましょう。

node server.js

そしてhttp://localhost:3000にアクセスし、Hello World!と表示されていれば成功です。

次に、上記のコードをURLに応じて処理先を変更できるように修正します。

var http = require('http');
var url = require("url");

var server = http.createServer(function(req, res) {
  var pathname = url.parse(req.url).pathname;

  if ('/' == pathname) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.write('Hello World!');
    res.end();
  }

  if ('/user' == pathname) {
    //省略
  }

});

server.listen(3000, function() {
    console.log('listening on port 3000');
});

まず、require("url")でurlを解析するNodeコアモジュールを読み込みます。 これもNode.jsがインストールされた際に、一緒にインストールされているので改めてnpmからインストールする必要はありません。 url.parse(req.url).pathnameでリクエストしたURLのpathnameをとりだし、さらにif ('/' == pathname)でpathnameに応じて処理を分けます。

ただ上記ではHTTPリクエストのGETメソッドの処理しか書かれていません。これも書き分ける必要がでてくるでしょう。 まずserver.jsと同じ階層にindex.htmlを作成して以下を記述してください。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
    <h1>index</h1>
    <p>入力してください</p>
    <form method="post" action="/result">
        <input type="text" name="result">
        <input type="submit">
    </form>
</body>
</html>

HTTPリクエストのメソッドで処理を分岐させると、1例ですが下記のようになります。先ほどのserver.jsに上書きしてみましょう。

var http = require('http');
var url = require("url");
var fs = require('fs');
var querystring = require('querystring');

var server = http.createServer(function(req, res) {
  var pathname = url.parse(req.url).pathname;

  switch (pathname) {

    case '/':
      if (req.method === 'GET') {
        fs.readFile('./index.html', 'UTF-8', function(err, data){
          res.writeHead(200, {'Content-Type': 'text/html'});
          res.end(data);
        });
      }
    break;

    case '/result':
      if (req.method === 'POST') {
        var body = '';
        req.on('data', function(chunk) {
          body += chunk;
        });

        req.on('end',function(){
          var form = querystring.parse(body);
          var text = form.result;
            fs.readFile('./index.html', 'UTF-8', function(err, data){
                res.writeHead(200, {'Content-Type': 'text/html'});
                res.end('「'+ text + '」と入力しました。');
            });
        });
      }
    break;

  }
});

server.listen(3000, function() {
    console.log('listening on port 3000');
});

fsモジュールとquerystringモジュールは新しくインストール不要です。 fsモジュールはファイルを読み書きする際に必要です。上記では、fs.readFileでindex.htmlに読み書きするために使っています。 querystringは文字列をオブジェクトに変換するモジュールです。querystring.parse(body)でリクエストbodyを文字列からオブジェクトに変換しています。

pathnameで処理を分岐したうえで、さらにif (req.method === 'GET')とif (req.method === 'POST')でGETとPOSTに処理を分けています。 リクエストがあるたびにdataイベントが発火するので、onメソッドにバインドしてコールバック関数にリクエストがあったときの処理を記述しています。

req.on('data', function(chunk) {
  body += chunk;
});

上記ではPOSTメソッドのリクエストがあった際、formで渡されてきたchunkをbody変数に格納しています。 コードを実行して、http://localhost:3000にアクセスしてみましょう。 簡単なフォームが表示されたと思います。何らかの文字〇〇を入力して送信ボタンを押してみましょう。「〇〇」と入力しました。と表示されれば成功です。

まとめ

今回は、Express.jsの導入やNode.jsの概要に触れました。
やや回り道に思えたかもしれませんが、Express.jsで複雑なアプリケーションを作成しようとするならNode.jsの知識が必要になります。 Express.jsを使えば、冗長なアプリケーションを簡潔に記述することができます。
次回は、Express.jsについて詳しく見ていきます。

アスタミューゼでは、エンジニア・デザイナーを募集中です。ご興味のある方は遠慮なく採用サイトからご応募ください。お待ちしています。

 

Re:ゼロから始めるJavaScript入門

今回初めて開発者ブログを担当させていただきます、 Scalaでバックエンドの開発をしているaxtstar(@axtstart)と申します。

以後お見知りおき頂ければ幸いです。

今日はScalaの話ではなく、 Scalaは私よりも詳しい方にお任せして JavaScriptの話題をさらりと取り上げてみたいと思います。

弊社では、勉強会という名目で開発・デザインの各社員が持ち回りで、調べたことや、興味のあることを発表する機会があります。 ネタに特に制限は無く、業務に関係していなくても構いません(もちろん関係していても構いません)。

社内提供用apiの技術的背景や、Scalaの新機能の紹介、参加したテック系カンファレンス (もちろんテック系のカンファレンスへの参加は業務のうちです。) のトレンド、またDocker、AlphaGo等、巷で話題になった内容を掘り下げて発表された方もいらっしゃいます。

今回の内容はその中で発表した内容をブログ向けに加筆修正したものです。

ゼロから始めるJavaScript

私が初めてJavaScriptを触ったのは、ASP(Active Server Pages)がまだ普通に使われていた頃です。 その後チョコチョコと扱う機会があったのですが、 概ね持っていた印象は下記のようなものでした。

  • スクリプト言語なのでエディタで書くためミスに気づきにくい
  • テストをwebブラウザを介して行うので煩雑、面倒。
  • ブラウザ毎に挙動が違うため、条件分岐が(当然ながらテストも)多くなってくる
  • prototype等、特有の書き方がわからない・よく間違う
  • ちょっとしたミスですぐ動かなくなる

サーバサイドを扱っていると、(前職ではASP.NETを扱っていることが多かったのですが) その違いが大きすぎて、JavaScriptってなんだかとっつきにくいというか、 なんとなく敬遠していました。

ちなみにASP.NETで使うC#の印象は下記のようなものでした。

  • コンパイル言語かつIDEにVisualStudioを使う為、Intellisenseによる強力な補正が働くためミスを軽減できる
  • テストはNUnitにより、コード内での網羅がわかる
  • Delphiの開発者が作ったため、オブジェクト指向的な書き方が容易

そんな印象からか、JavaScriptはとにかくなるべくなら見てみないふりをしていました なるべく使用しないような設計を選択する心理的バイアスがかかっていました。

再会のJavaScript

そんな印象だったJavaScriptですが、AjaxやjQuery、JSONの登場により確実な進化を遂げてきて、 更にNode.jsのようなサーバサイドの処理をJavaScriptで行うライブラリが登場したことで、サーバサイドエンジニアという意味合いも揺らいできたかと思います。

ご存知の通り、ECMAScriptの仕様が活発に検討されるようになり、本家 と言われる部分にも大幅な仕様変更がES6で入ったことで、 JavaScriptを取り巻く環境は大幅に変わりました。

タイトルに書いた通り、私がそうであったように、かつてJavaScriptを使っていて、 最近その世界に戻ってきた方には、何だかさっぱり様変わりしていて、 まさに再度ゼロからの入門が必要な状況になっているように感じていました。

約束した環境は遠く

まず、エディタのみを使って、何かJavaScriptだけで作ってみることで、実際に私が感じていたとっつきにくさが本当か確認してみました。

さらっと「確認してみました」と書きましたが、実際は相当時間がかかりました。

↓作ったもの↓

(html5+jQueryで動作しているので、古いブラウザでは動作しないと思います。)

黒選択時は盤面をクリックまたはタッチでゲームが始まります。 白選択時はstartボタンでコンピュータからゲームが始まります。 コンピュータはランダムで打ちます(アルゴリズムは全く考えていません)。




とにかく、HTML+JavaScriptだけで書いてみました。 ここに置いています。

これをエディタだけで書くのは、 二度とやりたくない かなり無理があるなというのが本音です。 やはり何か考え直さないとこのとっつきにくさは改善されないのは確かでした。

JavaScript入門のリスタート

調査した結果、以下の方法で、JavaScriptを整備する環境を構築してみることにしました。

こう変える 備考 おすすめ度
何かのEditor Visual Studio Code 下記 ★★★
なかった IntelliSense、コードスニペット VSCodeで実現 ★★★
alert埋め込みデバッグ エディタ上でデバッグ VSCodeで実現 ★★★
prototype class ES6化のため、トランスパイラが必要。ミスの低減。 ★★
function arrow functions ES6化、多用は逆に可読性を下げるかも
文字列を加算 template string ES6化、可読性の向上

Visual Studio Code(VSCode)は2015年にMicrosoftがElectronをベースに作成した、エディタです。 *1 名前からあのVisual Studioを想像してしまいますが、こちらは IDEではなく、マルチプラットフォームで動く、エディタです。 Atomとよく似ています。 *2

下記からVisualStdio Codeをダウンロード・インストールします。 code.visualstudio.com

F1キーを押して下記のようにすると、拡張機能のインストールができます。

ext install Javascript

f:id:astamuse:20160622091808p:plain

続けて以下もインストールします。

ext install Babel ES6/ES7

ext install Chrome

ext install eslint

VisualStudioとよく似ている機能としてはIntelliSense があり、コード補完や、クラスのメンバ関数などを一覧から、選択、コードへの貼り付けができるようになっており、生産性の向上が期待できます。

またIDEではないので、起動はかなり早いです。 (正直に言うと、エディタにしては遅いかもしれないですが。。)

下記はIntelliSenseで自分の作ったclassのメンバを確認している図

f:id:astamuse:20160622091210p:plain

デバッグ機能もかなり洗練されていて、 下図のボタンをクリックすると、.vscodeディレクトリに、 launch.jsonという名のボイラープレートが生成され、必要な部分を変更するだけで デバッグ機能が動作するようになります。

f:id:astamuse:20160622101246p:plain

Chromeデバッグの設定例

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Launch reversi.html with sourcemaps",
      "type": "chrome",
      "request": "launch",
      "file": "${workspaceRoot}/reversi.html",
      "sourceMaps": true,
      "webRoot": "${workspaceRoot}"
    }
  ]
}

デバッグ時の画面(chrome)

f:id:astamuse:20160623114221p:plain

もう見ただけで、生産性が向上した気分になります(笑)。

ES6がかった方法

上記の環境が出来上がった後、実際に元のソースをES6に対応させることにしました。

Chromeなどの最新のブラウザは既にES6の機能をほぼほぼ実装しており、ブラウザ毎の対応状況は こちらから確認することができます。

CoffeeScriptやTypeScriptなどから広がった考え方、手法にトランスパイラというものがありますが、 サーバサイドのJavaやC#もソースに変換処理(コンパイル)が必要という意味で、似たようなものがあります。

ES6のトランスパイラはBabelが有名で、かつてES6toES5と呼ばれており、 文字通り、ECMAScript6(ES6)のjsソースをECMAScript5(ES5)に変換することで、 より多くのブラウザで動作するようにするツールのことです。

今回はNode.jsを導入することで、これらの環境を整えました。

Node.js

Node.jsを上記からインストール後、npmで下記コマンドでbabel などをインストールしました。

npm install -g eslint webpack babel-loader babel-core babel-preset-es2015

今回ES6化したものは

prototype –> class

classはprototypeのシンタックスシュガー(糖衣構文)として実装されたES6機能です。

  • prototype
var yellowbase = function(_baseName, _rpt, _iwidth){
}
yellowbase.prototype = {
},
init:function( _baseName ,_rpt,_iwidth){
}
yellowbase.prototype.create.prototype=yellowbase.prototype;
  • class
export class othelloBase {
  constructor(_cssBase,  _rpt, _iwidth){
    return this;
  }
  init( _baseName ,_rpt,_iwidth){
  }
}

冗長だった記述がすっきりまとまった感が半端ないです。

function –> arrow functions

ScalaやC#ではおなじみ、Java8で導入されたラムダ式を用いた匿名関数の記法です。

  • function
$("#" + this.baseName).on('fire', function(){ox.draw();});
  • arrow functions
$(`#${this.baseName}`).on('fire', () => {ox.draw();});

すっきりしますね。

文字列結合 –> Template String

ScalaではInterpolationと呼ばれる、文字列の展開を行うシンタックスシュガーです。

  • 文字列結合
var cssSelector="input[name='c']";
var cssCheck= cssSelector + ": checked";
yourColor = Number($(cssCheck).val());
  • Template String
b.yourColor = Number($(`${cssCheck}:checked`).val());

こちらも意味的に分かりやすくなり、すっきりします。

このように、ES6を用いると、かなり冗長な記法を回避できることがわかりました。

こちらに上記のリバーシのソースをES6に対応したコードに修正したものを置いてあります。

また、ES6は2015年に仕様化されたECMAScriptの仕様ですが、現在ES7の仕様も検討中(もしかしたらこの記事を見ている頃にはもう出ているかもしれません。)のようです。

ES7の面白そうな記法にC#ではおなじみのasync/awaitというものがあり、非同期処理に関するもので、仕様の行方が気になります。

Re:ゼロから始めるJavaScript入門

このように、JavaScriptがモダンな開発手法をどんどん取り入れており、 コード補完、デバッグ、静的コード分析を手軽に行えるエディタの登場もあって、 ES6以降は他の言語と変わらないような、生産性の高い記述方法を取れることがわかりました。

もちろん、まだまだ巷には古いブラウザも存在しており、トランスパイラの精度の問題など、プロジェクトで本格的に使うにはまだまだ実験的な部分も大いにあるのですが、それでも、 以前と比較して、サーバサイドの開発者であっても違和感なく、JavaScriptの開発を進めていける環境が整ってきたように思います。

これを機に再度、入門を行って知見を広げるのも良いかと思いブログにまとめてみました。 何かの参考になれば幸いです。

また機会があれば非同期処理やテストなど、他の部分を掘り下げるのも良いなと、感じています。

最後になりましが、 アスタミューゼでは現在、エンジニア・デザイナーを募集中です。 興味のある方はぜひ 採用サイト からご応募ください。

参考にさせていただいた資料・Webサイトなど

*1:最近、正式版である1.0版が出ました。

*2:AtomもElectronベースで、こちらの方が古くからあるため利用者も多いようです。

Copyright © astamuse company, ltd. all rights reserved.