オリジナルKdB(科目検索)を作ってみよう -番外3- GCP Cloud Functions編

### これまでの記事
- [オリジナルKdB(科目検索)を作ってみよう -1- Node.jsセットアップ編](https://qiita.com/tkkrr/items/2f0d93b6d0c758a88037)
- [オリジナルKdB(科目検索)を作ってみよう -2- パース編](https://qiita.com/tkkrr/items/d8a87b4f598b1b107266)
- [オリジナルKdB(科目検索)を作ってみよう -3- データで遊ぶ編](https://qiita.com/tkkrr/items/8c0f66312212420114a0)
- [オリジナルKdB(科目検索)を作ってみよう -4- Express.jsでWEBアプリことはじめ編](https://qiita.com/tkkrr/items/5cafa77c104b11d76a16)
- [オリジナルKdB(科目検索)を作ってみよう -5- Express.jsでWEBアプリ整形編](https://qiita.com/tkkrr/items/9ea97ee9b2823e3a381e)
- [オリジナルKdB(科目検索)を作ってみよう -6- 本番環境Herokuにデプロイ編](https://qiita.com/tkkrr/items/db58c25ac65da30531e9)
- [オリジナルKdB(科目検索)を作ってみよう -番外1- FaaS下準備編](https://qiita.com/tkkrr/items/077dd30091b24e64b86b)
- [オリジナルKdB(科目検索)を作ってみよう -番外2- AWS Lambda編](https://qiita.com/tkkrr/items/e67227bcb15c1a08bb2b)

<img width="1241" alt="スクリーンショット 2019-02-22 16.11.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/245014/3d0c6b57-d3a9-1be1-4166-f9068a2f9771.png">

# この記事を読む前に
ある特定の人にしかわからない単語が出現する可能性が高いです。あらかじめご了承ください。

### この記事での開発環境
- MacOS 10.14.3
- Visual Studio Code 1.31.1
- Node.js LTS 10.15.1 (GCP Cloud Functionsでは6.x)

# はじめに
「オリジナルKdB(科目検索)を作ってみよう」の番外編です。これまではExpress.jsは使わず、**サーバレス**なシステムを作っていきましょう。シリーズでやっていたようにExpress.jsでエンヤコラはやらずに、**関数を作る**だけで簡単にサービスを作ることができます。

#### 前提条件
- GCP(Google)のアカウントを持っていること
- node.jsの開発環境があること

# AWS Lambda用の関数を作成
まずはじめにGCP Cloud FunctionsではNode.js(ver 6.x)のみがサポートされています。他の言語で描きたい場合はAWS LambdaやIBMCloud, Azure等の利用をオススメします。(なお、GCP Cloud FunctionsではPython3.7やGo1.11がベータ版として提供されています。)

特に複雑な処理は行わないのでGoogleCloud-SDKを使わずに作れます。
それではindex.jsを作りましょう。

```javascript:index.js
// GCPでは「exports.〇〇」とすることで好きな命名ができる。
// AWS Lambdaの時みたいに (event,callback) => ... もできるが
// 簡単な関数では (req, res) => ... の方が簡潔で早い
exports.csvparse = (req, res) => {

    // リクエストのクエリ文字列から「?search=〇〇」の値を変数に格納
    const str = req.query.search
    
    // -番外1- で作ったJSONデータの読み込み
    const json = require("./data")
    
    // 正規表現オブジェクトを作成、filterで検索
    const reg = new RegExp( str )
    const filterCourse = json.subjects.filter( (value) => {
        return value.name.match(reg)
    })

    // データ転送量削減のために最初の5件のみにする
    const resJson = {
        subjects: filterCourse.splice(0, 5)
    }
    
    // HTTPステータス200(success) でレスポンスを返す
    res.status(200).send( JSON.stringify(resJson) )
};
```

※GCP Cloud Functionsではデータ転送量が多くなるほど、実行時間が長くなるほどお金がかかります。そのためresponseを5件に絞り、JSON.stringfy()のコストとデータ転送量を削減しています。

## 補足
ぱっと見でわかると思いますが、Express.jsの時に書いたコードと大きく変わることなく記述できていることがわかると思います。これはシンプルなHTTPレスポンス処理を採用しているからです。細かい部分ではExpress.jsと記述方法が異なりますので注意してください(req.queryの部分とか)

## lambda関数のローカル実行テスト
Googleの方で提供されているエミュレータを使います。
こちらを参考にしました → https://cloud.google.com/functions/docs/emulator

**※エミュレートできる環境はNode.js 6.xのみ。PythonやGo, Node.js 8.xはエミュレートできません。**

まずはエミュレータをダウンロードします。

```shell
$ npm install -g @google-cloud/functions-emulator
$ functions --version   # 入っていることを確認
1.0.0-beta.5
```

そしたらエミュレータを起動します

```shell
$ functions start
```
これで起動しました。
ちなみに**エミュレータを終了するときは`functions stop`と入力**すればOKです

次はエミュレータ環境にデプロイします。

```shell
$ functions deploy csvparse --trigger-http

# 何かしら表示される。
# 「Function csvparse deployed.」と表示されていればOK
```

それではテストしてちゃんとレスポンスが返ってくるか確認します。
今回はクエリ文字列を直接入力できないので、以下のようにペイロードとして渡します。

```shell
$ functions call csvparse --data='{"query":{"search":"生物"}}'
```

ちゃんと検索結果が表示されたらOKです。
Zipファイルに圧縮してアップロードの準備をしましょう。

```shell
$ zip -r test.zip index.js data.js node_modules
```

# GCP Cloud Functions の準備
GCPのアカウントを作ったら、GCPのコンソールページにいきます。

<img width="1440" alt="スクリーンショット 2019-03-05 15.53.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/245014/c2cd2e98-cce1-ba2e-6a64-b08a82bbd418.png">
<img width="1440" alt="スクリーンショット 2019-03-05 15.53.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/245014/92b21e74-614f-5db6-0dd9-2cfbd5a32d93.png">
<img width="1440" alt="スクリーンショット 2019-03-05 16.06.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/245014/a378cce7-d4bb-7ccc-dd3d-af6a9b1b8706.png">
<img width="1440" alt="スクリーンショット 2019-03-05 16.11.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/245014/1af5a4cc-57c3-19b8-8889-d116947d17e8.png">

無事にリンクが発行できたのでリンクの最後に「?search=〇〇」を追加してアクセスしてみましょう！

# APIが完成した！
<img width="1440" alt="スクリーンショット 2019-03-03 17.12.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/245014/6e1f447a-844b-f451-5bc9-69fdd8a86594.png">

APIのURLにクエリ文字列を指定して実行すると実際にレスポンスが返ることがわかります。
AWS Lambdaよりも少し簡単に実装できましたね！

GCPも`gcloud`というCLIがあり、そちらを使えばコマンドライン上で全ての処理が可能です。興味のある方はぜひ使ってみてください！

なお、今回もAPIをオープンアクセス可能な状態で作成しましたが、API-Keyを発行するなり、ユーザ認証をするなど、何かしらのセキュリティを設けたほうが確実で安全です。ここでの説明は割愛させていただきますが最低限のマナーなので気をつけたほうがいいです。

参考記事↓

- [API キーの使用](https://cloud.google.com/docs/authentication/api-keys?hl=ja&visit_id=636873714397873142-3703690316&rd=1)
- [API キーを使用する理由と条件](https://cloud.google.com/endpoints/docs/when-why-api-key?hl=ja)

質問等はコメントでお願いします！
ありがとうございました！

## 今回のあとがき
こんなに簡単ならAWS Lambdaを使わなくていいのでは...?
いえいえ、そんな簡単な話じゃないんです。確かにGCPの操作は簡単で便利ですが、設定の細かさで言ったらAWSに軍配があがるケースが多いです。細かい設定をすることで本当の意味での最適化を行うことができるのでコストカットには最適でしょう。

でもやっぱFirebaseとかSearchAPIとかGoogleMapsAPIとかとか。Googleにしかない強みがこれでもかというくらいあるんですよね。やっっぱGoogleはつよい。

それでもクラウドも適材適所ってことです。いろんなサービスを使って仲良くしていきましょう。