Serverless Frameworkをつかってバーコード画像APIを作ってみた

結構前にAPI Gatewayがバイナリデータをサポートしたってことで
Serverless Frameworkの勉強がてらになんとなくバーコードAPIを作ってみました。

#Serverless Frameworkのインストール
[Serverless Frameworkならすぐ出来るよね AWSでサーバーレス（API+Lambda[java]を簡単セットアップ）](
http://qiita.com/ukitiyan/items/945d84282726d3fe2c2f#serverless-framework%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)
とか参考にセットアップします。
※因みに私はWINDOWS環境です:grinning:

```shell-session
E:\workspaces\qiita>npm ls -g serverless
C:\Users\hasegawa\AppData\Roaming\npm
`-- serverless@1.13.2
```

#Serverless Frameworkでつくる

##サービスをつくる
[Quick Start](https://serverless.com/framework/docs/providers/aws/guide/quick-start/)

とか見ながら

```shell-session
E:\workspaces\qiita>sls create --template aws-nodejs --path barcode
Serverless: Generating boilerplate...
Serverless: Generating boilerplate in "E:\workspaces\qiita\barcode"
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.13.2
 -------'

Serverless: Successfully generated boilerplate for template: "aws-nodejs"

E:\workspaces\qiita>
```

##ライブラリをインストール
とりあえず `npm init`

```shell-session
E:\workspaces\qiita>cd barcode

E:\workspaces\qiita\barcode>npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (barcode)
version: (1.0.0)
description:
entry point: (handler.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to E:\workspaces\qiita\barcode\package.json:

{
  "name": "barcode",
  "version": "1.0.0",
  "description": "",
  "main": "handler.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this ok? (yes) yes

E:\workspaces\qiita\barcode>
```

でバーコードのライブラリをインストール。
[bwip-js](https://github.com/metafloor/bwip-js)を使います。

```shell-session
E:\workspaces\qiita\barcode>npm i bwip-js -S
barcode@1.0.0 E:\workspaces\qiita\barcode
`-- bwip-js@1.3.2
  `-- argv@0.0.2
```

次にバイナリレスポンスの設定をしてくれるライブラリをインストール。
[serverless-apigwy-binary](https://github.com/ryanmurakami/serverless-apigwy-binary)

```shell-session
E:\workspaces\qiita\barcode>npm i -S serverless-apigwy-binary
barcode@1.0.0 E:\workspaces\qiita\barcode
`-- serverless-apigwy-binary@0.1.0
  `-- bluebird@3.5.0
```


ローカルでAPI Gatewayの動作確認したいので [serverless-offline](https://github.com/dherault/serverless-offline)もインストールします。

```shell-session
E:\workspaces\qiita\barcode>npm i serverless-offline -D
barcode@1.0.0 E:\workspaces\qiita\barcode
`-- serverless-offline@3.14.0
  +-- babel-register@6.24.1
  | +-- babel-core@6.24.1
  | | +-- babel-code-frame@6.22.0
  | | | +-- chalk@1.1.3
  | | | | +-- ansi-styles@2.2.1
  .
  .
  .
```
でserverless.ymlに `plugins...` を追加

```yaml:serverless.yml
service: barcode
plugins: 
 - serverless-apigwy-binary
 - serverless-offline
```

##コードを書く
[サンプル](https://github.com/metafloor/bwip-js#nodejs-image-generator)をコピペして

```js:handler.js
'use strict';
var bwipjs = require('bwip-js');
bwipjs.loadFont('Inconsolata', 108,
            require('fs').readFileSync('node_modules/bwip-js/fonts/Inconsolata.otf', 'binary'));

module.exports.hello = (event, context, callback) => {
    var param = event.query;
    bwipjs.toBuffer({
            bcid:        param.bcid        || 'code128',       // Barcode type
            text:        param.text        || '0123456789',    // Text to encode
            scale:       param.scale       || 3,               // 3x scaling factor
            height:      param.height      || 10,              // Bar height, in millimeters
            includetext: param.includetext || true,            // Show human-readable text
            textxalign:  param.textxalign  || 'center',        // Always good to set this
            textfont:    param.textfont    || 'Inconsolata',   // Use your custom font
            textsize:    param.textsize    || 13               // Font size, in points
        }, function (err, png) {
            if (err) {
                callback(null, "[BadRequest] " + err);
            } else {
                // `png` is a Buffer
                callback(null, png.toString('base64'));
            }
        });
};
```
バイナリの返却はbase64エンコードします。

次にserverless.ymlの `events` の箇所のコメントアウトをはずして下記のようにします

```yaml:serverless.yml
    events:
      - http:
          path: barcode
          method: get
          integration: lambda
          contentHandling: CONVERT_TO_BINARY
          request:
            parameters:
              querystrings:
                bcid: false
                text: false
                scale: false
                height: false
                includetext: false
                textxalign: false
                textfont: false
                textsize: false
```
integrationのデフォルトは `lambda-proxy` なので `lambda`を追記します。

*※lambda-proxyの方が簡単なんですがどうしてもうまくいきませんでした。。
バイナリがサポートされてない感じです
https://forums.aws.amazon.com/thread.jspa?threadID=243584&tstart=0*

##この辺でローカルで確認する
Serverless Offlineを動かして

```shell-session
E:\workspaces\qiita\barcode>sls offline start
Serverless: Starting Offline: dev/us-east-1.

Serverless: Routes for hello:
Serverless: GET /barcode

Serverless: Offline listening on http://localhost:3000
```
ブラウザでhttp://localhost:3000/barcode
にリクエストを出してこんな感じになればＯＫです。

```shell-session
Serverless: [200] "iVBORw0KGgoAAAANSUhEUgAAAQ4AAABzCAMAAABepBw8AAAAHnRFWHRTb2Z0d2FyZQBid2lwLWpzLm1l
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Hic7ZlrQFVVFsfP/4omvsAHyEWBKc2rUhlqkg5oKr7CULuKSmhKimnpzAiaZiOiYoNmiqaGTmSlaGomaIT5SinSxrERcqxselA6
/V+yCbnNQOsmi+3pbwDi7c9JYhZB3fI4ql+PmfLfwYWGZlWokOoMStNvBgnK3UrkjThVbEiXjUqtjmlCJuOiz2Nnidr7S89fkNT
```
因みに２回目以降のリクエストはエラーになります・・。
Serverless Offlineをリスタートするしかないです。
（理由は調べてません。。:sweat_smile:）

##デプロイ

```shell-session
E:\workspaces\qiita\barcode>sls deploy
Serverless: Packaging service...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (5.48 MB)...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
..............................
Serverless: Stack update finished...
Service Information
service: barcode
stage: dev
region: us-east-1
api keys:
  None
endpoints:
  GET - https://xxxxxxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/barcode
functions:
  hello: barcode-dev-hello
Serverless: Setting up content handling in AWS API Gateway (takes ~1 min)...
Serverless: Deploying content handling updates to AWS API Gateway...
Serverless: AWS API Gateway Deployed

```

でendpointsをブラウザでたたくと

![sample.png](https://qiita-image-store.s3.amazonaws.com/0/132516/d95fce2a-e9b1-cb44-0596-5f5c54dd695b.png)

・・・あれ？Content-Typeがイケてないようです。。

`Accept: image/png`
つけるとＯＫですね。

![sample4.png](https://qiita-image-store.s3.amazonaws.com/0/132516/370fd940-3c09-575b-4f71-45b6d55206dd.png)


この辺りは調べて追記することにします。。
※追記　無理かも。。　https://forums.aws.amazon.com/thread.jspa?threadID=246629