IBM Cloud FunctionsでAPIを作成する

# はじめに
IBM Cloud Functions上に作成したActionを、APIとして呼び出す方法にはいくつかあります。
WEBアクションを有効にするのが一番お手軽ですが、指定出来ることが少なく、
APIゲートウェイを使用するの若干手間がかかりますが、より複雑な指定が可能になります。

以下では、それぞれの方法での作り方について、覚書としてまとめます。

# サンプルのアクション
APIとして呼び出して実行するサンプルのアクションは次の通りです。
パラーメータとして渡された`name`に対して、`Hello name!`を返します。
`name`の指定がなかった場合は、`Hello Someone!`を返します。

```javascript
function main(params) {
    let name = (params.name) ? params.name : 'Someone';
	return {message : 'hello '+name+'!' };
}
```

# 方法1.Webアクション
一番簡単な方法は、Webアクションを有効にすることです。
アクション名横の「Web Action」をクリックします。
![web-action-enable.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/7c7452d1-49c8-1817-723f-b45a85501bc1.png)

「Enable as Web Action」にチェックを入れて、Saveします。
![web-action-enable2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/d46e250c-591c-e066-e395-987c8d4d2b51.png)

下のURLがAPIの呼び出し先となります。
Webアクションが対応しているHTTPメソッドは、`GET,POST,PUT,PATCH,DELETE`になります。
<font color="Red">注意:</font> 上記URLを呼び出しても上手くいかない場合は、末尾に`.json`を付けて呼び出して下さい。

呼び出し結果は次のようになります。

```bash
$ curl -X GET https://jp-tok.functions.cloud.ibm.com/api/v1/web/XXXXX/default/testAction.json
{
  "message": "hello Someone!"
}
curl -X GET https://jp-tok.functions.cloud.ibm.com/ap/v1/web/XXXXX/default/testAction.json?name=Smith
{
  "message": "hello Smith!"
}
```
この方法の欠点は、トークン認証の仕組みがないので、URLを知っていれば誰でも実行できてしまう点です。

# 方法2.IAMトークンを使ったREST API
IAMトークンを利用すれば、APIの実行に認証の仕組みを導入できます。
IBM CloudのIAMトークンの取得方法はいくつか存在しますが、ここでは、サービスIDを使います。
他の方法は、こちらの記事を参考にして下さい。
https://qiita.com/testnin2/items/3a4ca8a1a2b79b713c48

## サービスIDのAPIキーの取得
「管理」>「アクセス(IAM)」>「サービスID」から、API呼び出ししたいアクションがデプロイされている、Cloud Functionsの名前空間を選択します。
「作成」ボタンが有効でない場合は、右上のメニューからロックを解除します。
![unlock.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/bf2a413d-40aa-3a08-6f85-44c734d2d889.png)
![unlock2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/80829ef0-8148-c714-0920-7bc579050689.png)

ここで、対象の名前空間のAPIキーを作成します。
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/757f974a-2ed0-2adf-fa6f-4e52dc8cf635.png width=300>
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/76dbdd31-baf3-09b4-cbe3-28d121587f54.png width=500>

## IAMトークンの取得
サービスIDのAPIキーを取得したら、次のページを参考に、curlをコピペしてきて実行します。
https://cloud.ibm.com/docs/iam?topic=iam-iamtoken_from_apikey&locale=ja

```bash
curl -k -X POST \
  --header "Content-Type: application/x-www-form-urlencoded" \
  --header "Accept: application/json" \
  --data-urlencode "grant_type=urn:ibm:params:oauth:grant-type:apikey" \
  --data-urlencode "apikey=<apikey>" \
  "https://iam.cloud.ibm.com/identity/token"
```
次のようなjsonが帰ってくるので、`access_token`の値を使用します。

```json
{"access_token":"XXXXX","refresh_token":"XXXXX","token_type":"Bearer"}
```

## IAMトークンを使ってAPI実行
WebアクションのURLを確認したページに、同じくIAMを利用する場合のURLが記載されています。
基本的に記載のcurlをそのまま実行すれば、アクションが実行されます。
![REST-Action.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/3a23c60a-4198-2826-70d6-5f65644c1a55.png)
返ってきたjsonの`response`の中に実行結果が含まれています。

```json
  "response": {
    "result": {
      "message": "hello Someone!"
    },
    "size": 28,
    "status": "success",
    "success": true
  }
```

この方法の欠点は認証の仕組みがあるものの、IAMのトークンの有効期限が60分なので、再取得する必要がある点です。
参考：https://cloud.ibm.com/docs/iam?topic=iam-iamtoken_from_apikey&locale=ja
また、2019年11月現在、`-d`などで、パラメータを渡しても上手く動作しないようです。
参考：https://stackoverflow.com/questions/56616014/how-to-fix-error-parameter-name-when-using-ibm-cloud-functions-rest-api

# 方法3.APIゲートウェイ
APIゲートウェイを使う方法は、これまでの方法よりも複雑な指定が可能になります。

- APIのパスの指定
- HTTPメソッドの指定
- 複数のアクションを1つのAPIとしてラップ
- レート制限の導入
- APIキーと秘密鍵による認証
- OAuthによる認証

など、他にもありますが、ここでは単純にAPIキーを発行して、外部ユーザーがIBM Cloud Functionのアクションを、APIとして実行出来る状態にします。

## APIの作成
Cloud Functionsのトップから、「API」を選択して、「Creat Cloud Functions API」を選択します。
![createAPI.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/cba542c8-ae37-969c-d256-f9767a17d940.png)

### API情報の設定
APIゲートウェイでは、WebアクションやIAMを使う方法よりも、多くのことが設定可能です。
ここでは、外部から実行するために、基本的な設定のみ行います。

#### API basics
APIの名前とAPIのベースのパスを指定します。
![basics.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/41f052ac-6e7d-805f-e99b-f211b4854ba8.png)

#### Operations
呼び出すアクションと、呼び出し先のパス、呼び出す際のHTTPメソッドなどを指定します。
![operation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/addb58bf-94f3-1295-016a-c548c6b9ee55.png)

複数のパス・メソッド・アクションを指定して、1つのAPIとしてラップすることもできます。
![operation2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/24c0a3aa-57cb-f2cc-c581-2e561e5a17c2.png)

### Application authentication
APIの認証の仕組みを指定します。認証なし・APIキーのみ・APIと秘密鍵の3種類が指定できます。
![AppAuth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/a980bb82-2c9a-64d1-86e9-1acd9c550fd1.png)

### Rate limiting
レート制限の設定をします。ここでは、1秒間に1000回までとしています。
![Rating.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/f9c85771-7a3b-c68a-86fd-ac72a9e2de21.png)


### APIキーの取得
設定が済み、APIを作成したら、APIキーを取得します。(最大5つまで作成可能です。)
「共有」から「Sharing Outside of Cloud Foundry organization」から外部ユーザー用のAPIキーを取得します。
![outside-key.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/da9972ab-77d6-1c93-82f9-b94069cd2aac.png)
API Portal Linkから、このAPIの簡単なドキュメントが参照できます。
ただし、2019年11月現在IAMの名前空間では利用できません。
補足のCF-basedの名前空間の作成方法を参考にして下さい。

(参考)
APIの認証設定で秘密鍵を指定した場合は、内部ユーザー向けの「Sharing within Cloud Foundry organization」から秘密鍵が取得できます。
![inside-key.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/04338f8a-1544-c78d-926c-defb4e1dd2bb.png)

## APIの実行
APIキーを取得したら、Application authenticationの欄にしたがって、ヘッダーにAPIキーを入れて、Operationsの通り、HTTPメソッドを実行します。
ルートのURLは、「サマリー」から確認できます。
![API-Route.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/77eaa409-b965-b1ad-db52-45c677c5caed.png)

上記で設定した情報は次の通りでした。

|セクション|設定項目|設定値|
|:--|:--|:--|
|Operations|パス|/test|
|Operations|HTTPメソッド|GET|
|Application authentication|APIキーパラメータ名|X-IBM-Client-Id|

したがって、次のようなcurlで実行し、次のような実行結果となります。

```bash
$ curl -X GET https://XXXXX.jp-tok.apigw.appdomain.cloud/API-TEST/test \
 -H 'X-IBM-Client-Id:XXXXX'
{
  "message": "hello Someone!"
}

$ curl -X GET https://XXXXX.jp-tok.apigw.appdomain.coud/API-TEST/test?name=Smith \
 -H 'X-IBM-Client-Id:XXXXX'
{
  "message": "hello Smith!"
}
```
<font color="Red">注意:</font> 上手く実行されない場合はWEBアクションを有効にしてみて下さい。

# [補足]CF-basedの名前空間の作成
「管理」>「アカウント」から「Cloud Foundryの組織」を選びます。
既に存在するCloud Foundryの組織を選ぶか、「作成」から新規作成を行います。
![CF-org.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/afa66ab6-e62f-9cce-d872-cb756fb3b069.png)
「スペースの追加」から新しく名前空間を作ります。
![add-space.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/c1b92b09-de8a-4320-9403-7e07bb332e9a.png)
<font color="Red">注意:</font> シドニーはIBM Cloud Functionsでは使用できないので、米国南部(ダラス)などを選んで下さい。
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526658/8342d996-deab-51d6-cf2a-0fc1cd35e0b8.png width=300>