はやさがたりない。

へっぽこぷろぐらまのメモログ

APIGateway の MappingTemplate

CURLでテストすると勝手に「Content-Type: application/x-www-form-urlencoded」がつけられるのでちゃんと自分でヘッダーを指定しましょう。

MappingTemplateが正常に動作するようになったらこんなエラーが返ってくるようになった。

{"message": "Could not parse request body into json: Unexpected character (\',\' (code 44)): expected a valid value (number, String, array, object, \'true\', \'false\' or \'null\')\n at [Source: [B@6812cadd; line: 4, column: 16]"}

指定したMappingTemplateはこんな感じ。

#set($inputRoot = $input.path('$'))
{
  "type": "$inputRoot.type",
  "address": "$inputRoot.address",
  "location": $inputRoot.location,
  "title": "$inputRoot.title",
  "description": "$inputRoot.description"
}

「$inputRoot.location」がnullの時とかにJSONとしてフォーマットがおかしくなるからこんなエラーが返ってくる。

一旦こんな形式にしてみたけども

#set($inputRoot = $input.path('$'))
{
  "type": "$inputRoot.type",
  "address": "$inputRoot.address",
  "location": {
    "lat": $inputRoot.location.lat,
    "lon": $inputRoot.location.lon
  },
  "title": "$inputRoot.title",
  "description": "$inputRoot.description"
}

これでも「$inputRoot.location.lat」がnullの時にNG。
でもここは数値にしたいから""でも囲うこともできない。
そうするとここでわざわざ#ifとかでnullの時は設定しないー的なことをする必要があるってこと?
だったらもうソース側でやればよくね?

いまいちよくわからん。

serverless での エラーマッピングの仕方。

そもそものエラーの返し方はこちら。

return context.done(new Error("invalid type :" + type ));

レスポンスコードを変えたりしたい時は、 s-function.json の responses をいじる 。
こんな感じでコンソール上の「Lambda Error Regex」を「selectionPattern」に 設定する。
デフォルトだとstackTraceがそのまま出てしまうのでテンプレートを設定している。

          "responses": {
            "400": {
              "statusCode": "400",
              "selectionPattern": "invalid type.*",
              "responseTemplates": {
                "application/json": "#set($inputRoot = $input.path('$'))\n{\n  \"errorMessage\": \"$inputRoot.errorMessage\",\n  \"errorType\": \"$inputRoot.errorType\"#if($context.stage == \"development\"),\n  \"stackTrace\": $inputRoot.stackTrace#end\n\n}"
              }
            },

テンプレートを見やすく整形するとこんな感じ。
stageでstackTraceの出力を切り替えている。

#set($inputRoot = $input.path('$'))
{
  "errorMessage": "$inputRoot.errorMessage",
  "errorType": "$inputRoot.errorType"#if($context.stage == "development"),
  "stackTrace": $inputRoot.stackTrace
#end
}

serverlessのmappingtemplateのフォーマットメモ

responseTemplatesのforeachとかは、ここの記述フォーマットに従っている。

Apache Velocity - VTL Reference


jsonのフィールドの先頭に「_」があった時にうまくテンプレートに適用できなかった。

そんな時はここを見るといい感じ。

JSONPath - XPath for JSON

serverlessで一つのfunctionをrunする方法

公式ドキュメントには

sls function run myModule/myFunctions#functionOne

って書いてあるけど実際にそれでやっても

Serverless: Select a function to run: 
    myFunctions
  >   functionOne
      functionTwo

ってなっちゃうのでもやもやしてた。

こう書いたら選択しなくてもテストできるのですな。

sls function run -n functionOne

serverless さわってみた

所感

serverless (旧名JAWS)の使い勝手を調べてみた。
結果としては割といい感じ。
serverlessならansibleとかもいらなくなる!
AWSのリソースもserverlessの中のCloudFormationでOKだぜ!!みたいな。。?
まだまだドキュメントは少ないけど、もうちょっと勉強していこうと思う。。

手順

初期セットアップ

※Node 4系以上が必要

$ sudo npm install serverless -g
$ mkdir ~/.aws
$ vi ~/.aws/credentials
--
[default]
aws_access_key_id=<<アクセスキー>>
aws_secret_access_key=<<シークレットアクセスキー>>
--
$ vi ~/.aws/config
--
[default]
region = ap-northeast-1
--

作ってみる

$ serverless project create
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                          serverless.com, v.0.0.12
`-------'
Serverless: Enter a project name:  (serverlessN1A2rULrx) akira-test
Serverless: Enter a project domain (used for serverless regional bucket names):  (myapp.com) akira-test.com
Serverless: Enter an email to use for AWS alarms:  (me@myapp.com) 
Serverless: Select a region for your project: 
    us-east-1
    us-west-2
    eu-west-1
  > ap-northeast-1
Serverless: Select an AWS profile for your project: 
  > default
Serverless: Creating a project region bucket on S3: serverless.apnortheast1.akira-test.com...  
Serverless: Creating CloudFormation Stack for your new project (~5 mins)...  
Serverless: Successfully created project: akira-test  
  • 作られたもの
    • S3 
    • IAM Group
    • IAM Role
  • ディレクトリ構成
-rw-r--r--  1 arika  staff   11 12 13 21:38 README.md
-rw-r--r--  1 arika  staff  136 12 13 21:38 admin.env
drwxr-xr-x  4 arika  staff  136 12 13 21:38 back
drwxr-xr-x  3 arika  staff  102 12 13 21:38 cloudformation
drwxr-xr-x  2 arika  staff   68 12 13 21:38 plugins
-rw-r--r--  1 arika  staff  495 12 13 21:41 s-project.json

CloudFormationでIAMあたりを作っているっぽ。S3は別。
CloudFormationのテンプレートが自動生成されて、そこにIAMのロールやらの定義が書かれている。
んで、おそらくここにAWS elsaticsearchの設定とかを書いておいてserverless resources deployってやるとデプロイされる、とかができるための仕組みだと思う。
AWSのリソースの管理もできるということですね。素晴らしい。

モジュールとかファンクションとかを作る

$ serverless module create -m greetings -f hello
Serverless: Successfully created hello function.  
Serverless: Installing "serverless-helpers" for this module via NPM...  
serverless-helpers-js@0.0.3 node_modules/serverless-helpers-js
└── dotenv@1.2.0
Serverless: Successfully created new serverless module "greetings" with its first function "hello"  

$ ls -l back/modules/greetings/
total 16
drwxr-xr-x  5 arika  staff  170 12 13 21:49 hello
drwxr-xr-x  3 arika  staff  102 12 13 21:49 lib
drwxr-xr-x  3 arika  staff  102 12 13 21:49 node_modules
drwxr-xr-x  2 arika  staff   68 12 13 21:49 package
-rw-r--r--  1 arika  staff  359 12 13 21:49 package.json
-rw-r--r--  1 arika  staff  277 12 13 21:49 s-module.json

backっていうディレクトリの下にhelloっていうのができて、
そこのhandler.jsってやつがメイン処理っぽい。。。?

back/modules/greetings/hello/handler.js
'use strict';

/**
 * Serverless Module: Lambda Handler
 * - Your lambda functions should be a thin wrapper around your own separate
 * modules, to keep your code testable, reusable and AWS independent
 * - 'serverless-helpers-js' module is required for Serverless ENV var support.  Hopefully, AWS will add ENV support to Lambda soon :)
 */

// Require Serverless ENV vars
var ServerlessHelpers = require('serverless-helpers-js').loadEnv();

// Require Logic
var lib = require('../lib');

// Lambda Handler
module.exports.handler = function(event, context) {

  lib.respond(event, function(error, response) {
    return context.done(error, response);
  });
};

...いや、こっちか?でもlibの下にメイン処理があるもんか?
おそらくhandlerはいじらずここだけ意識していじればいいぜって感じか?

back/modules/greetings/lib/index.js
/**
 * Lib
 */

module.exports.respond = function(event, cb) {

  var response = {
    message: "Your Serverless function ran successfully!"
  };

  return cb(null, response);
};

lambdaへのデプロイ

$ serverless function deploy
Serverless: Deploying functions in "development" to the following regions: ap-northeast-1  
Serverless: Successfully deployed functions in "development" to the following regions: ap-northeast-1  

api gatewayへのデプロイ

$ serverless endpoint deploy
Serverless: Deploying endpoints in "development" to the following regions: ap-northeast-1  
Serverless: Successfully deployed endpoints in "development" to the following regions:  
Serverless: ap-northeast-1 ------------------------  
Serverless:   GET - https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/development/greetings/hello  

ローカルでのテスト

ローカルでのテストも簡単にできるのは素晴らしい。

$ serverless function run
Serverless: Running GreetingsHello...  
Serverless: -----------------  
Serverless: Success! - This Response Was Returned:  
Serverless: {"message":"Your Serverless function ran successfully!"}  

リンク集

http://docs.serverless.com/v0/docs
http://qiita.com/mokemokechicken/items/f81c886053f7d81a655d