12.3. Node.js 関数の開発
Node.js 関数プロジェクトを作成 したら、指定のテンプレートを変更して、関数にビジネスロジックを追加できます。これには、関数呼び出しと返されるヘッダーとステータスコードの設定が含まれます。
12.3.1. 前提条件
- 関数を開発する前に、OpenShift Serverless Functions の設定 の手順を完了している。
12.3.2. Node.js 関数テンプレート構造
Knative (kn
) CLI を使用して Node.js 関数を作成すると、プロジェクトディレクトリーは典型的な Node.js プロジェクトのようになります。唯一の例外は、関数の設定に使用される追加の func.yaml
ファイルです。
http
および event
トリガー関数のテンプレート構造はいずれも同じです。
テンプレート構造
. ├── func.yaml 1 ├── index.js 2 ├── package.json 3 ├── README.md └── test 4 ├── integration.js └── unit.js
- 1
func.yaml
設定ファイルは、イメージ名とレジストリーを判断するために使用されます。- 2
- プロジェクトに関数を 1 つエクスポートする
index.js
ファイルを追加する必要があります。 - 3
- テンプレート
package.json
ファイルにある依存関係に限定されるわけではありません。他の Node.js プロジェクトと同様に、別の依存関係を追加できます。npm 依存関係の追加例
npm install --save opossum
デプロイメント用にプロジェクトをビルドすると、これらの依存関係は作成したランタイムコンテナーイメージに含まれます。
- 4
- 統合およびテストスクリプトは、関数テンプレートに含まれます。
12.3.3. Node.js 関数の呼び出しについて
Knative (kn
) CLI を使用して関数プロジェクトを作成する場合に、CloudEvents に応答するプロジェクト、または単純な HTTP 要求に応答するプロジェクトを生成できます。Knative の CloudEvents は HTTP 経由で POST 要求として転送されるため、関数タイプはいずれも受信 HTTP イベントをリッスンして応答します。
Node.js 関数は、単純な HTTP 要求で呼び出すことができます。受信要求を受け取ると、関数は context
オブジェクトで最初のパラメーターとして呼び出されます。
12.3.3.1. Node.js コンテキストオブジェクト
関数は、context
オブジェクトを最初のパラメーターとして渡して呼び出されます。このオブジェクトは、受信 HTTP 要求情報へのアクセスを提供します。
この情報には、HTTP リクエストメソッド、リクエストと共に送信されたクエリー文字列またはヘッダー、HTTP バージョン、およびリクエスト本文が含まれます。CloudEvent
を含む受信リクエストは、CloudEvent の受信インスタンスをコンテキストオブジェクトに添付し、context.cloudevent
を使用してアクセスできるようにします。
12.3.3.1.1. コンテキストオブジェクトメソッド
context
オブジェクトには、データの値を受け入れ、CloudEvent を返す cloudEventResponse()
メソッドが 1 つあります。
Knative システムでは、サービスとしてデプロイされた関数が CloudEvent を送信するイベントブローカーによって呼び出される場合に、ブローカーが応答を確認します。応答が CloudEvent の場合、このイベントはブローカーによって処理されます。
コンテキストオブジェクトメソッドの例
// Expects to receive a CloudEvent with customer data function handle(context, customer) { // process the customer const processed = handle(customer); return context.cloudEventResponse(customer) .source('/handle') .type('fn.process.customer') .response(); }
12.3.3.1.2. CloudEvent data
受信要求が CloudEvent の場合は、CloudEvent に関連付けられたデータがすべてイベントから抽出され、2 番目のパラメーターとして提供されます。たとえば、以下のように data プロパティーに JSON 文字列が含まれる CloudEvent が受信されると、以下のようになります。
{ "customerId": "0123456", "productId": "6543210" }
呼び出されると、context
オブジェクトの後の関数の 2 番目のパラメーターは、customerId
プロパティーと productId
プロパティーを持つ JavaScript オブジェクトになります。
署名の例
function handle(context, data)
この例の data
パラメーターは、customerId
および productId
プロパティーが含まれる JavaScript オブジェクトです。
12.3.3.1.3. 任意のデータ
関数は CloudEvents
だけでなく任意のデータを受信できます。たとえば、任意のオブジェクトを本文に指定した POST を使用して関数を呼び出すことができます。
{ "id": "12345", "contact": { "title": "Mr.", "firstname": "John", "lastname": "Smith" } }
この場合、関数を次のように定義できます。
function handle(context, customer) { return "Hello " + customer.contact.title + " " + customer.contact.lastname; }
関数に連絡先オブジェクトを指定すると、次の出力が返されます。
Hello Mr. Smith
12.3.3.1.4. サポートされるデータタイプ
CloudEvents には、JSON、XML、プレーンテキスト、バイナリーデータなど、さまざまなデータ型を含めることができます。これらのデータ型は、それぞれの形式で関数に提供されます。
- JSON データ: JavaScript オブジェクトとして提供されます。
- XML データ: XML ドキュメントとして提供されます。
- プレーンテキスト: 文字列として提供されます。
- バイナリーデータ: Buffer オブジェクトとして提供されます。
12.3.3.1.5. 関数内の複数のデータ型
Content-Type ヘッダーをチェックし、それに応じてデータを解析することで、関数がさまざまなデータ型を処理できることを確認します。以下に例を示します。
function handle(context, data) { if (context.headers['content-type'] === 'application/json') { // handle JSON data } else if (context.headers['content-type'] === 'application/xml') { // handle XML data } else { // handle other data types } }
12.3.4. Node.js 関数の戻り値
関数は、有効な JavaScript タイプを返すことも、戻り値を持たないこともできます。関数に戻り値が指定されておらず、失敗を指定しないと、呼び出し元は 204 No Content
応答を受け取ります。
関数は、CloudEvent または Message
オブジェクトを返してイベントを Knative Eventing システムにプッシュすることもできます。この場合、開発者は CloudEvent メッセージング仕様を理解したり実装したりする必要はありません。返された値からのヘッダーおよびその他の関連情報は抽出され、応答で送信されます。
例
function handle(context, customer) { // process customer and return a new CloudEvent return new CloudEvent({ source: 'customer.processor', type: 'customer.processed' }) }
12.3.4.1. プリミティブ型を返す
関数は、文字列、数値、ブール値などのプリミティブを含む、任意の有効な JavaScript 型を返すことができます。
文字列を返す関数の例
function handle(context) { return "This function Works!" }
この関数を呼び出すと、次の文字列が返されます。
$ curl https://myfunction.example.com
This function Works!
数値を返す関数の例
function handle(context) { let somenumber = 100 return { body: somenumber } }
この関数を呼び出すと、次の数値が返されます。
$ curl https://myfunction.example.com
100
ブール値を返す関数の例
function handle(context) { let someboolean = false return { body: someboolean } }
この関数を呼び出すと、次のブール値が返されます。
$ curl https://myfunction.example.com
false
プリミティブをオブジェクトにラップせずに直接返すと、空の本文を持つ 204 No Content
ステータスコードが返されます。
プリミティブを直接返す関数の例
function handle(context) { let someboolean = false return someboolean }
この関数を呼び出すと、次の結果が返されます。
$ http :8080
HTTP/1.1 204 No Content Connection: keep-alive ...
12.3.4.2. 返されるヘッダー
headers
プロパティーを return
オブジェクトに追加して応答ヘッダーを設定できます。これらのヘッダーは抽出され、呼び出し元に応答して送信されます。
応答ヘッダーの例
function handle(context, customer) { // process customer and return custom headers // the response will be '204 No content' return { headers: { customerid: customer.id } }; }
12.3.4.3. 返されるステータスコード
statusCode
プロパティーを return
オブジェクトに追加して、呼び出し元に返されるステータスコードを設定できます。
ステータスコード
function handle(context, customer) { // process customer if (customer.restricted) { return { statusCode: 451 } } }
ステータスコードは、関数で作成および出力されるエラーに対して設定することもできます。
エラーステータスコードの例
function handle(context, customer) { // process customer if (customer.restricted) { const err = new Error(‘Unavailable for legal reasons’); err.statusCode = 451; throw err; } }
12.3.5. Node.js 関数のテスト
Node.js 関数は、コンピューターに対してローカルでテストできます。kn func create
を使用して関数を作成する際に作成されるデフォルトプロジェクトには、簡単なユニットテストおよびインテグレーションテストが含まれる test フォルダーがあります。
前提条件
- OpenShift Serverless Operator および Knative Serving がクラスターにインストールされている。
-
Knative (
kn
) CLI がインストールされている。 -
kn func create
を使用して関数を作成している。
手順
- 関数の test フォルダーに移動します。
テストを実行します。
$ npm test
12.3.6. liveness および readiness プローブの値の上書き
Node.js 関数の liveness
および readiness
プローブの値を上書きできます。これにより、関数に対して実行されるヘルスチェックを設定できます。
前提条件
- OpenShift Serverless Operator および Knative Serving がクラスターにインストールされている。
-
Knative (
kn
) CLI がインストールされている。 -
kn func create
を使用して関数を作成している。
手順
関数コードで、次のインターフェイスを実装する
Function
オブジェクトを作成します。export interface Function { init?: () => any; 1 shutdown?: () => any; 2 liveness?: HealthCheck; 3 readiness?: HealthCheck; 4 logLevel?: LogLevel; handle: CloudEventFunction | HTTPFunction; 5 }
- 1
- サーバーの起動前に呼び出される初期化関数。この関数はオプションであり、同期する必要があります。
- 2
- サーバーの停止後に呼び出される shutdown 関数。この関数はオプションであり、同期する必要があります。
- 3
- liveness 関数。サーバーが生きているかどうかを確認するために呼び出されます。この関数はオプションであり、サーバーが稼動している場合は 200/OK を返す必要があります。
- 4
- readiness 関数。サーバーがリクエストを受け入れる準備ができているかどうかを確認するために呼び出されます。この関数はオプションであり、サーバーが準備できている場合は 200/OK を返すはずです。
- 5
- HTTP リクエストを処理する関数。
たとえば、以下のコードを
index.js
ファイルに追加します。const Function = { handle: (context, body) => { // The function logic goes here return 'function called' }, liveness: () => { process.stdout.write('In liveness\n'); return 'ok, alive'; }, 1 readiness: () => { process.stdout.write('In readiness\n'); return 'ok, ready'; } 2 }; Function.liveness.path = '/alive'; 3 Function.readiness.path = '/ready'; 4 module.exports = Function;
Function.liveness.path
およびFunction.readiness.path
の代わりに、LIVENESS_URL
およびREADINESS_URL
環境変数を使用してカスタムエンドポイントを指定できます。run: envs: - name: LIVENESS_URL value: /alive 1 - name: READINESS_URL value: /ready 2
新しいエンドポイントを
func.yaml
ファイルに追加して、Knative サービスのコンテナーに適切にバインドされるようにします。deploy: healthEndpoints: liveness: /alive readiness: /ready
12.3.7. Node.js コンテキストオブジェクトのリファレンス
context
オブジェクトには、関数開発者が利用可能なプロパティーが複数あります。これらのプロパティーにアクセスすると、HTTP 要求に関する情報が提供され、出力がクラスターログに書き込まれます。
12.3.7.1. log
出力をクラスターロギングに書き込むために使用可能なロギングオブジェクトを提供します。ログは Pino logging API に準拠します。
ログの例
function handle(context) { context.log.info(“Processing customer”); }
kn func invoke
コマンドを使用して、この関数にアクセスできます。
コマンドの例
$ kn func invoke --target 'http://example.function.com'
出力例
{"level":30,"time":1604511655265,"pid":3430203,"hostname":"localhost.localdomain","reqId":1,"msg":"Processing customer"}
ログレベルは、fatal
、error
、warn
、info
、debug
、trace
、または silent
のいずれかに設定できます。これを実行するには、config
コマンドを使用してこれらの値のいずれかを環境変数 FUNC_LOG_LEVEL
に割り当てて、logLevel
の値を変更します。
12.3.7.2. query
要求のクエリー文字列 (ある場合) をキーと値のペアとして返します。これらの属性はコンテキストオブジェクト自体にも表示されます。
サンプルクエリー
function handle(context) { // Log the 'name' query parameter context.log.info(context.query.name); // Query parameters are also attached to the context context.log.info(context.name); }
kn func invoke
コマンドを使用して、この関数にアクセスできます。
コマンドの例
$ kn func invoke --target 'http://example.com?name=tiger'
出力例
{"level":30,"time":1604511655265,"pid":3430203,"hostname":"localhost.localdomain","reqId":1,"msg":"tiger"}
12.3.7.3. ボディー
要求ボディー (ある場合) を返します。要求ボディーに JSON コードが含まれている場合は、属性が直接利用できるように解析されます。
ボディーの例
function handle(context) { // log the incoming request body's 'hello' parameter context.log.info(context.body.hello); }
curl
コマンドを使用してこの関数を呼び出すことができます。
コマンドの例
$ kn func invoke -d '{"Hello": "world"}'
出力例
{"level":30,"time":1604511655265,"pid":3430203,"hostname":"localhost.localdomain","reqId":1,"msg":"world"}
12.3.7.4. ヘッダー
HTTP 要求ヘッダーをオブジェクトとして返します。
ヘッダーの例
function handle(context) { context.log.info(context.headers["custom-header"]); }
kn func invoke
コマンドを使用して、この関数にアクセスできます。
コマンドの例
$ kn func invoke --target 'http://example.function.com'
出力例
{"level":30,"time":1604511655265,"pid":3430203,"hostname":"localhost.localdomain","reqId":1,"msg":"some-value"}
12.3.7.5. HTTP 要求
- 方法
- HTTP 要求メソッドを文字列として返します。
- httpVersion
- HTTP バージョンを文字列として返します。
- httpVersionMajor
- HTTP メジャーバージョン番号を文字列として返します。
- httpVersionMinor
- HTTP マイナーバージョン番号を文字列として返します。