CloudFunctionsをServerless Framework & TypeScriptで試してみる

## やったこと

Serverless Frameworkを使って CloudFunctionを動かしてみました。
試した内容は下記の通りです。

- TypeScriptで書けるようにしてみる
- serverless.ymlの設定で環境変数を利用する
- 日本のリージョンにDeployする

**実際に利用したコード**
https://github.com/selmertsx/study/tree/master/serverless/cloudfunction-sls-sample

## 前提

https://serverless.com/framework/docs/providers/google/guide/quick-start/

上記チュートリアルを実行して、nodejsのコードをdeploy & invokeできるようにしてある前提で話を進めます。

## TypeScriptで書けるようにする

https://github.com/prisma/serverless-plugin-typescript
このpluginを利用します。

手順は簡単で、下記の手順を踏むだけで設定可能です

- serverless.yml のpluginsに `serverless-plugin-typescript` を追加する
- 指定されたフォーマットでtsconfig.jsonの設定をする
- 既存のコードをTypeScriptに置き換える
- (options) package.jsonのmain fieldを書き換える

```serverless.yml
plugins:
  - serverless-google-cloudfunctions
  - serverless-plugin-typescript
```

```tsconfig.json
// Note: outDir と rootDir optionsを上書きしないこと
{
  "compilerOptions": {
    "target": "es5",
    "outDir": ".build", 
    "moduleResolution": "node",
    "lib": ["es2015"],
    "rootDir": "./"
  }
}
```

もし起点となるコードが index.ts でなければ、package.jsonのmain fieldを下記のように書き換える必要があります。

```
// handler.tsを起点にしたい場合
{
  // ...
  "main": "handler.js",
  // ..
}
```

## serverless.ymlの設定で環境変数を利用する

https://serverless.com/framework/docs/providers/google/guide/variables/

公式ドキュメントを見ると、ymlやjsとして別のファイルに切り出したり、serverless.dev.ymlのように環境毎にymlを分けたりする方法が書かれています。今回はgitにcommitしたくない設定の管理がしたかったので、違う方法を模索しました。

https://serverless.com/framework/docs/providers/aws/guide/variables/

awsの方のGuideを見てみると、下記のような機能がありました。

> o reference environment variables, use the ${env:SOME_VAR} syntax in your serverless.yml configuration file. It is valid to use the empty string in place of SOME_VAR. This looks like "${env:}" and the result of declaring this in your serverless.yml is to embed the complete process.env object (i.e. all the variables defined in your environment).

これについてgoogleでも使えないかと試してみたところ、普通に使えたので今回はそれを利用しました。

```serverless.yml
service: cloudfunction-sls-sample
provider:
  name: google
  project: ${env:PROJECT}
```

## 日本のリージョンにDeployする

cloud functionsでServerless Frameworkを利用し、regionを何も指定せずにdeployをすると us-central1にdeployがされます。
deploy先のregionをserverless.ymlで設定していきましょう。
deployする先の指定は、serverless-google-cloudfunctionsの**v2.0.0** から出来るようになっています。
けれども、sls コマンドでinstallされるversionは**v1.2.0**なので、pluginのバージョンを上げる必要があります。

https://github.com/serverless/serverless/blob/63b8dafbeb7bd463acf9fe9a4f5ec51c7e972928/lib/plugins/create/templates/google-nodejs/package.json#L12

```package.json
"devDependencies": {
  "serverless-google-cloudfunctions": "^2.0.0",
  "serverless-plugin-typescript": "^1.1.5"
}
```

その後、serverless.ymlの値を書き換えて実行してみます。

```serverless.yml
service: cloudfunction-sls-sample
provider:
  name: google
  region: asia-northeast1
  runtime: nodejs8
  project: ${env:PROJECT}
```

実行結果がこちらになります。

```
$ sls deploy
service: cloudfunction-sls-sample
project: xxx
stage: dev
region: us-central1

Deployed functions
first
  https://us-central1-xxx.cloudfunctions.net/http
```

ぱっと見ると**us-central1にdeployされていてギョっとしますが**、cliを使って実際にdeployされているregionを確認してみると、ちゃんと**asia-northeast1になっている**ことが確認できます。

```
gcloud beta functions describe http --region asia-northeast1
availableMemoryMb: 256
entryPoint: http
httpsTrigger:
  url: https://asia-northeast1-xxx.cloudfunctions.net/http <==ここをチェック
labels:
  goog-dm: sls-cloudfunction-sls-sample-dev
name: projects/xxx/locations/asia-northeast1/functions/http
runtime: nodejs8
serviceAccountEmail: xxx@appspot.gserviceaccount.com
sourceArchiveUrl: gs://sls-cloudfunction-sls-sample-dev-xxx/serverless/cloudfunction-sls-sample/dev/xxx-2018-09-25T10:08:07.390Z/cloudfunction-sls-sample.zip
status: ACTIVE
timeout: 60s
updateTime: '2018
```

## AWS Lambdaと比較した雑感

- localでの動作確認について、lambdaはpluginで提供されているが、cloud functionsはまだない。
  - https://github.com/serverless/serverless-google-cloudfunctions/issues/74
  - [エミュレータ](https://cloud.google.com/functions/docs/emulator?hl=ja)はあるらしい。今度試してみよう
- LambdaではTypeScriptテンプレートがあるので、特に何の指定もしなくて良い
- Lambdaは起動するためのeventsが豊富
    - cloud functionsはhttpとpub subだけ
    - これがcloud functionsのデメリットとなるかは、pub subを触ってみないとなんとも言えない