Serverless Serverside jq

  • 19
    いいね
  • 2
    コメント

これはなに

jq コマンドをサーバサイドで動くようにすることで、jq をクラウドに昇華させることを目的としたキータドキュメントです。
さらに、クラウドコンピューティングの発展の到達点とも言える概念であるサーバレスアーキテクチャを取り込み、極限までクラウド昇華させたサーバサイド・サーバレス・jqを提案します。

jq について

jq とは JSON をいい感じにパースしたり加工したりしてくれる素晴らしいコマンドです。

こんな感じのコマンドです。

$ echo '{"items":[{"item_id":1,"name":"すてきな雑貨","price":2500},{"item_id":2,"name":"格好いい置物","price":4500}]}' \
| jq .
{
  "items": [
    {
      "item_id": 1,
      "name": "すてきな雑貨",
      "price": 2500
    },
    {
      "item_id": 2,
      "name": "格好いい置物",
      "price": 4500
    }
  ]
}
$ echo '{"items":[{"item_id":1,"name":"すてきな雑貨","price":2500},{"item_id":2,"name":"格好いい置物","price":4500}]}' \
| jq '.items[].name'
"すてきな雑貨"
"格好いい置物"

詳しくは私の jq コマンドを使う日常のご紹介 をご覧いただくか、 マニュアル を参照してください。

ローカルに押しやられていた jq

jq のポテンシャル

冒頭で jq は JSON を加工したりするコマンドと説明しました。jqは、加工・参照のために、アトリビュートをパターンで指定したり、オブジェクトをパイプで繋ぐことで複雑な加工を指定できます。一見JSONに特化した便利なDSLに見えるだけですが、実はプログラミング言語といって良いほどの機能を持っております。jq は、 map, reduce, join, 再入可能な関数定義、データの生成など豊富な機能を有しています。

これはつまり、「サーバサイドの言語として活用できる。」そう考えたのです。以下のエントリはまたまたワタクシのエントリで恐縮すが、 jq でズンドコを実装した例です。プログラミング言語である事が実感できると思います。

jq を取り込む

ライブラリとしての jq

jq を取り込みましょう。jq には API が公開されています。 jq.h をインクルードし、 libjq をリンクすることで、 jq を開発しているプログラムに取り込むことが出来ます。jq を Ruby に取り込んだ例として ruby-jq はあまりにも有名と思います。

npm package としての jq

今回、jq をサーバサイドで動かすべく、 node のネイティブエクステンションを開発しました。npmには、既に node-jq と呼ばれるパッケージが存在していましたが、 これは、jq コマンドを実行するだけのものです。

node-jq から jq プロセスを起動して実行するサーバアプリが真のサーバサイドを名乗って良いものか。悩み検討しました。結果、やはり node のネイティブエクステンションを開発し、 node プロセスと共に生きることが出来る形態を取れるようにすることとしました。

node-jq-ext 爆誕

jq のネイティブエクステンションとして、node-jq-ext を開発しました。

npm のサイトの README.md が適当すぎますね。時間がなさすぎたのです。

なお、 node のネイティブエクステンションのためのライブラリにはバージョンの違いがあるために、バージョン間の差異を吸収する Native Abstractions for Node.js(通称nan) を活用しました。

$ echo '[{"aa":1},{"aa":2}]' | jq '.[] | .aa'
1
2

は、下記のように JS で書けます。

const obj = new node_jq_ext.Jq('.[] | .aa')
assert.deepEqual(obj.parse('[{"aa":1},{"aa":2}]'), ['1','2'])

サーバサイド jq

npm パッケージにしてしまえば、jq をサーバサイドに移動することが出来ます。よかったね jq。

サーバレス・サーバサイド・jq

サーバレスアーキテクチャ == AWS Lambda。こういうとマサカリが多く飛んで来そうですが、jq を昇華させるためにあえてそう呼びます。また、ここにマサカリを投げる不毛みを乗り越えて投げてくる人もいないでしょう。

AWS Lambda に jq アプリをデプロイする

開発支援パッケージ

node-jq-ext があることで、jq アプリの開発が開けました。が、アプリをそのまま開発してしまっては、JS コードの中に jq コードが埋め込まれているだけの、ちょっとコレジャナイ感があるアプリができあがってしまいます。

そこで、サーバレス jq のためのパッケージ serverside-jq-serverless をさらに開発しました。これを利用することで、 node-jq-ext を利用したアプリケーション開発の生産性を向上させることができます。

これにより、 index.js に下記を記述するだけで Lambda 上で動くjqアプリケーションを記述することが出来ます。

get_lambda_function = require('serverside-jq-serverless');
export.handler = get_lambda_function.default('. | .key1');

Lambda に { key1: "hoge" } を投げると、 jq アプリにより { result: ["hoge"] } が返されます。

(本当は index.jq を置けばよくしたかったけど時間がなかったぉ…)

サンプル

下記のリポジトリにデプロイなどの gulp タスクを含めたサンプルLambdaアプリケーションを用意しました。

https://github.com/takeshinoda/sjs-sample

まとめ

ここでは jq をサーバサイドにもっていけることを示しました。ひたすら JSON をパースするサーバなどを構築するときに有効であるでしょう。

最後に感想

  • node のネイティブエクステンションの書き方を身につけられた
  • 久しぶりにC++書いて楽しかった
  • MacOS 用のコンパイルオプションは面倒くさい
  • Qiita ネタは jq と AWS Lambda ばかりで自分に発展がない懸念がでてきた
  • そんなに面白くない割に徹夜とかしたので、ネタのコストが高すぎた
  • jq をサーバサイドに持って行ってもろくなIO無いのでやめた方がいい
  • Serverless ほとんど関係なくてほんとすいません