12.4. TypeScript 関数の開発
TypeScript 関数プロジェクトを作成 したら、指定のテンプレートを変更して、関数にビジネスロジックを追加できます。これには、関数呼び出しと返されるヘッダーとステータスコードの設定が含まれます。
12.4.1. 前提条件
- 関数を開発する前に、OpenShift Serverless Functions の設定 の手順を完了している。
12.4.2. TypeScript 関数テンプレートの構造
Knative (kn
) CLI を使用して TypeScript 関数を作成すると、プロジェクトディレクトリーは典型的な TypeScript プロジェクトのようになります。唯一の例外は、関数の設定に使用される追加の func.yaml
ファイルです。
http
および event
トリガー関数のテンプレート構造はいずれも同じです。
テンプレート構造
. ├── func.yaml 1 ├── package.json 2 ├── package-lock.json ├── README.md ├── src │ └── index.ts 3 ├── test 4 │ ├── integration.ts │ └── unit.ts └── tsconfig.json
- 1
func.yaml
設定ファイルは、イメージ名とレジストリーを判断するために使用されます。- 2
- テンプレート
package.json
ファイルにある依存関係に限定されるわけではありません。他の TypeScript プロジェクトと同様に、別の依存関係を追加できます。npm 依存関係の追加例
npm install --save opossum
デプロイメント用にプロジェクトをビルドすると、これらの依存関係は作成したランタイムコンテナーイメージに含まれます。
- 3
- プロジェクトには、
handle
という名前の関数をエクスポートするsrc/index.js
ファイルが含まれている必要があります。 - 4
- 統合およびテストスクリプトは、関数テンプレートに含まれます。
12.4.3. TypeScript 関数の呼び出しについて
Knative (kn
) CLI を使用して関数プロジェクトを作成する場合に、CloudEvents に応答するプロジェクト、または単純な HTTP 要求に応答するプロジェクトを生成できます。Knative の CloudEvents は HTTP 経由で POST 要求として転送されるため、関数タイプはいずれも受信 HTTP イベントをリッスンして応答します。
TypeScript 関数は、単純な HTTP 要求で呼び出すことができます。受信要求を受け取ると、関数は context
オブジェクトで最初のパラメーターとして呼び出されます。
12.4.3.1. TypeScript コンテキストオブジェクト
関数を呼び出すには、context
オブジェクトを最初のパラメーターとして指定します。context
オブジェクトのプロパティーにアクセスすると、着信 HTTP 要求に関する情報を提供できます。
コンテキストオブジェクトの例
function handle(context:Context): string
この情報には、HTTP リクエストメソッド、リクエストと共に送信されたクエリー文字列またはヘッダー、HTTP バージョン、およびリクエスト本文が含まれます。CloudEvent
を含む受信リクエストは、CloudEvent の受信インスタンスをコンテキストオブジェクトに添付し、context.cloudevent
を使用してアクセスできるようにします。
12.4.3.1.1. コンテキストオブジェクトメソッド
context
オブジェクトには、データの値を受け入れ、CloudEvent を返す cloudEventResponse()
メソッドが 1 つあります。
Knative システムでは、サービスとしてデプロイされた関数が CloudEvent を送信するイベントブローカーによって呼び出される場合に、ブローカーが応答を確認します。応答が CloudEvent の場合、このイベントはブローカーによって処理されます。
コンテキストオブジェクトメソッドの例
// Expects to receive a CloudEvent with customer data export function handle(context: Context, cloudevent?: CloudEvent): CloudEvent { // process the customer const customer = cloudevent.data; const processed = processCustomer(customer); return context.cloudEventResponse(customer) .source('/customer/process') .type('customer.processed') .response(); }
12.4.3.1.2. コンテキストタイプ
TypeScript タイプの定義ファイルは、関数で使用する以下のタイプをエクスポートします。
エクスポートタイプの定義
// Invokable is the expeted Function signature for user functions export interface Invokable { (context: Context, cloudevent?: CloudEvent): any } // Logger can be used for structural logging to the console export interface Logger { debug: (msg: any) => void, info: (msg: any) => void, warn: (msg: any) => void, error: (msg: any) => void, fatal: (msg: any) => void, trace: (msg: any) => void, } // Context represents the function invocation context, and provides // access to the event itself as well as raw HTTP objects. export interface Context { log: Logger; req: IncomingMessage; query?: Record<string, any>; body?: Record<string, any>|string; method: string; headers: IncomingHttpHeaders; httpVersion: string; httpVersionMajor: number; httpVersionMinor: number; cloudevent: CloudEvent; cloudEventResponse(data: string|object): CloudEventResponse; } // CloudEventResponse is a convenience class used to create // CloudEvents on function returns export interface CloudEventResponse { id(id: string): CloudEventResponse; source(source: string): CloudEventResponse; type(type: string): CloudEventResponse; version(version: string): CloudEventResponse; response(): CloudEvent; }
12.4.3.1.3. CloudEvent data
受信要求が CloudEvent の場合は、CloudEvent に関連付けられたデータがすべてイベントから抽出され、2 番目のパラメーターとして提供されます。たとえば、以下のように data プロパティーに JSON 文字列が含まれる CloudEvent が受信されると、以下のようになります。
{ "customerId": "0123456", "productId": "6543210" }
呼び出されると、context
オブジェクトの後の関数の 2 番目のパラメーターは、customerId
プロパティーと productId
プロパティーを持つ JavaScript オブジェクトになります。
署名の例
function handle(context: Context, cloudevent?: CloudEvent): CloudEvent
この例の cloudevent
パラメーターは、customerId
および productId
プロパティーが含まれる JavaScript オブジェクトです。
12.4.4. TypeScript 関数の戻り値
関数は、有効な JavaScript タイプを返すことも、戻り値を持たないこともできます。関数に戻り値が指定されておらず、失敗を指定しないと、呼び出し元は 204 No Content
応答を受け取ります。
関数は、CloudEvent または Message
オブジェクトを返してイベントを Knative Eventing システムにプッシュすることもできます。この場合、開発者は CloudEvent メッセージング仕様を理解したり実装したりする必要はありません。返された値からのヘッダーおよびその他の関連情報は抽出され、応答で送信されます。
例
export const handle: Invokable = function ( context: Context, cloudevent?: CloudEvent ): Message { // process customer and return a new CloudEvent const customer = cloudevent.data; return HTTP.binary( new CloudEvent({ source: 'customer.processor', type: 'customer.processed' }) ); };
12.4.4.1. 返されるヘッダー
headers
プロパティーを return
オブジェクトに追加して応答ヘッダーを設定できます。これらのヘッダーは抽出され、呼び出し元に応答して送信されます。
応答ヘッダーの例
export function handle(context: Context, cloudevent?: CloudEvent): Record<string, any> { // process customer and return custom headers const customer = cloudevent.data as Record<string, any>; return { headers: { 'customer-id': customer.id } }; }
12.4.4.2. 返されるステータスコード
statusCode
プロパティーを return
オブジェクトに追加して、呼び出し元に返されるステータスコードを設定できます。
ステータスコード
export function handle(context: Context, cloudevent?: CloudEvent): Record<string, any> { // process customer const customer = cloudevent.data as Record<string, any>; if (customer.restricted) { return { statusCode: 451 } } // business logic, then return { statusCode: 240 } }
ステータスコードは、関数で作成および出力されるエラーに対して設定することもできます。
エラーステータスコードの例
export function handle(context: Context, cloudevent?: CloudEvent): Record<string, string> { // process customer const customer = cloudevent.data as Record<string, any>; if (customer.restricted) { const err = new Error(‘Unavailable for legal reasons’); err.statusCode = 451; throw err; } }
12.4.5. TypeScript 関数のテスト
TypeScript 関数は、お使いのコンピューターでローカルでテストできます。kn func create
を使用して関数を作成するときに作成されるデフォルトのプロジェクトには、いくつかの単純な単体テストと統合テストを含む test フォルダーがあります。
前提条件
- OpenShift Serverless Operator および Knative Serving がクラスターにインストールされている。
-
Knative (
kn
) CLI がインストールされている。 -
kn func create
を使用して関数を作成している。
手順
テストを実行していない場合は、最初に依存関係をインストールします。
$ npm install
- 関数の test フォルダーに移動します。
テストを実行します。
$ npm test
12.4.6. liveness および readiness プローブの値の上書き
TypeScript 関数の 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.4.7. TypeScript コンテキストオブジェクトの参照
context
オブジェクトには、関数開発者が利用可能なプロパティーが複数あります。これらのプロパティーにアクセスすると、着信 HTTP 要求に関する情報が提供され、出力がクラスターログに書き込まれます。
12.4.7.1. log
出力をクラスターロギングに書き込むために使用可能なロギングオブジェクトを提供します。ログは Pino logging API に準拠します。
ログの例
export function handle(context: Context): string { // log the incoming request body's 'hello' parameter if (context.body) { context.log.info((context.body as Record<string, string>).hello); } else { context.log.info('No data received'); } return 'OK'; }
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.4.7.2. query
要求のクエリー文字列 (ある場合) をキーと値のペアとして返します。これらの属性はコンテキストオブジェクト自体にも表示されます。
サンプルクエリー
export function handle(context: Context): string { // log the 'name' query parameter if (context.query) { context.log.info((context.query as Record<string, string>).name); } else { context.log.info('No data received'); } return 'OK'; }
kn func invoke
コマンドを使用して、この関数にアクセスできます。
コマンドの例
$ kn func invoke --target 'http://example.function.com' --data '{"name": "tiger"}'
出力例
{"level":30,"time":1604511655265,"pid":3430203,"hostname":"localhost.localdomain","reqId":1,"msg":"tiger"} {"level":30,"time":1604511655265,"pid":3430203,"hostname":"localhost.localdomain","reqId":1,"msg":"tiger"}
12.4.7.3. ボディー
要求ボディー (ある場合) を返します。要求ボディーに JSON コードが含まれている場合は、属性が直接利用できるように解析されます。
ボディーの例
export function handle(context: Context): string { // log the incoming request body's 'hello' parameter if (context.body) { context.log.info((context.body as Record<string, string>).hello); } else { context.log.info('No data received'); } return 'OK'; }
kn func invoke
コマンドを使用して、この関数にアクセスできます。
コマンドの例
$ kn func invoke --target 'http://example.function.com' --data '{"hello": "world"}'
出力例
{"level":30,"time":1604511655265,"pid":3430203,"hostname":"localhost.localdomain","reqId":1,"msg":"world"}
12.4.7.4. ヘッダー
HTTP 要求ヘッダーをオブジェクトとして返します。
ヘッダーの例
export function handle(context: Context): string { // log the incoming request body's 'hello' parameter if (context.body) { context.log.info((context.headers as Record<string, string>)['custom-header']); } else { context.log.info('No data received'); } return 'OK'; }
curl
コマンドを使用してこの関数を呼び出すことができます。
コマンドの例
$ curl -H'x-custom-header: some-value’' http://example.function.com
出力例
{"level":30,"time":1604511655265,"pid":3430203,"hostname":"localhost.localdomain","reqId":1,"msg":"some-value"}
12.4.7.5. HTTP 要求
- 方法
- HTTP 要求メソッドを文字列として返します。
- httpVersion
- HTTP バージョンを文字列として返します。
- httpVersionMajor
- HTTP メジャーバージョン番号を文字列として返します。
- httpVersionMinor
- HTTP マイナーバージョン番号を文字列として返します。
12.4.8. 次のステップ
- 関数を構築 して デプロイ します。
- 関数に関するロギングの詳細は、Pino API のドキュメント を参照してください。