RESTful API Proxy サーバーを Brunch で使う


SPA な開発をしていると、RESTful API 用の Proxy が欲しくなります。でも、そのために Apache 入れたり nginx 入れるのはちょっと違うよなと思っていて、Brunch 使っている人向けの情報です。

Brunch でローカルサーバーをカスタマイズ

brunch-config.coffee でサーバーを指定すればよろしい。

brunch-config.coffee
exports.config =
  # See http://brunch.io/#documentation for docs.
  files:
    javascripts:
      joinTo:
        'javascripts/app.js': /^app/
        'javascripts/vendor.js': /^(?!app)/

    stylesheets:
      joinTo: 'stylesheets/app.css'

    templates:
      joinTo: 'javascripts/app.js'

  server:
    path: 'local-server.coffee'
    run: yes

ローカルサーバーを書く

いろいろあると思いますが、オーソドックスに Express を使います。http proxy 用に request も使います。

local-server.coffee
express = require 'express'
sysPath = require 'path'
http = require 'http'
request = require 'request'

exports.startServer = (port, path, callback) ->
  app = express()
  app.use express.static path

  proxy = 'http://192.168.80.96:8080'
  api_endpoint = 'http://192.168.80.150:8002'

  request = request.defaults
    proxy: proxy

  app.all '/api/*', (req, res) ->
    req.pipe(request(api_endpoint + req.url)).pipe(res)

  # rewrite other resource to index.html
  app.all '/*', (req, res) ->
    res.sendFile sysPath.resolve sysPath.join path, 'index.html'

  server = http.createServer app
  server.listen parseInt(port, 10), callback
  server

実装は単純で、/api 宛てのリクエストを絶対 URL にして、request に pipe して結果を res に pipe。抽象度高すぎてしびれます。それ以外の URL については index.html を返すようにしてリロード対策。

この例では内部 proxy 指定してますけど、API サーバーに直接アクセス可能なら、いらない設定です。あとは、google maps など外部の API を呼ぶときに corporate proxy 経由しないとダメーなときに指定したりします。

はまりどころ

当初、proxy 用に http-proxy を使ってたんですが、内部 proxy を経由するとどうにもうまく動きませんでした。原因究明に疲れ果てた頃に request に出会い、試しに使ってみると拍子抜けするくらいあっさり成功。。。

下手に利用実績のあるプロダクトだと、なんとか動かそうと執着して時間を無駄にしてしまうことがあり、良くない傾向だなと反省しました。

参考