Atlas Function
GraphQL は廃止予定です。詳細はこちら。
Overview
Atlas Function は、アプリの動作を定義するためにユーザーが記述するサーバーサイドの JavaScript コードです。アプリの関数をクライアントから直接呼び出すことも、関数を自動的に統合して呼び出すサービスを定義することもできます。
関数は、他の関数を呼び出して、MongoDB Atlas クラスター内のデータを操作するための組み込みクライアントを含めることができます。関数はまた、便利なグローバル ユーティリティを含み、一般的な Node.js 組み込みモジュールをサポートし、npm レジストリから外部パッケージをインポートして使用することもできます。
exports = function(name) { return `Hello, ${name ?? "stranger"}!` }
関数はサーバーレス
アプリは関数が呼び出されると、コードを評価し結果を返す管理型アプリ サーバーにリクエストをルーティングします。このモデルでは関数はサーバーレスになるため、ユーザーがコードを実行するサーバーを配置・管理する必要はありません。代わりに、ユーザーは関数のソースコードを記述し、アプリが実行環境を取り扱います。
関数にはコンテキストが付属
関数は、その実行環境を反映したコンテキストの枠内で実行されます。コンテキストの例として、関数を呼び出したユーザー、関数の呼び出し方法、呼び出し時のアプリの状態が挙げられます。コンテキストを使用することで、ユーザー固有のコードの実行やアプリの他の部分との連携が可能になります。
関数コンテキストとの連携方法の詳細については、「コンテキスト」を参照してください。
関数を使用可能なケース
関数はユーザーが定義した任意の JavaScript コードを実行できるため、ほぼすべての目的で使用できます。レイテンシが低く、実行時間が短いタスク(データの移動、変換、検証など)は関数の一般的なユースケースです。また、外部サービスに接続したり、クライアント アプリケーションから詳しい実装情報を抽象化したりする目的でも関数を使用できます。
関数には、ユーザーが直接呼び出すものに加え、HHTTPS endpoints、Atlas Triggers、GraphQL のカスタム リゾルバ(GraphQL は廃止予定です。詳細はこちら)などのさまざまなサービス用にユーザーが記述するものもあります。これらのサービスでは、特定のイベントを処理するために関数が自動的に呼び出されます。たとえば、データベース Triggers で変更イベントが観察されるたびに、変更イベントを引数として関連する関数が呼び出されます。Trigger 関数を利用すると、変更イベントの情報にアクセスして、適宜、対応できます。
関数の記述方法
関数のコードは基本的に名前付きの JavaScript ソースファイルであるため、1 つの関数ファイルに複数の JavaScript 関数を定義できます。 このファイルは 1 つの JavaScript 関数をエクスポートする必要があり、呼び出しを受信したときのエントリポイントとして機能します。 関数を名前で呼び出すと、実際には関数のソースファイル内の exports
に割り当てられた JavaScript 関数が呼び出されます。
以下は、name
引数を受け取り、ログ メッセージを追加し、指定された名前にあいさつを返す単純な関数の例です。
exports = function Hello(name) { console.log(`Said hello to ${name}`); return `Hello, ${name}!`; };
最新の JavaScript 構文とインポート パッケージを使用すると、より複雑な関数を定義できます。
// You can use ES6 arrow functions const uppercase = (str) => { return str.toUpperCase(); }; // You can use async functions and await Promises exports = async function GetWeather() { // You can get information about the user called the function const city = context.user.custom_data.city; // You can import Node.js built-ins and npm packages const { URL } = require("url"); const weatherUrl = new URL("https://example.com"); weatherUrl.pathname = "/weather"; weatherUrl.search = `?location="${city}"`; // You can send HTTPS requests to external services const weatherResponse = await context.http.get({ url: url.toString(), headers: { Accept: ["application/json"], }, }); const { current, forecasts } = JSON.parse(weatherResponse.body.text()); return [ `Right now ${uppercase(city)} is ${current.temperature}°F and ${current.weather}.`, `Here's the forecast for the next 7 days:`, forecasts .map((f) => `${f.day}: ${f.temperature}°F and ${f.weather}`) .join("\n "), ].join("\n"); };
Right now NEW YORK CITY is 72°F and sunny. Here's the forecast for the next 7 days: Tuesday: 71°F and sunny Wednesday: 72°F and sunny Thursday: 73°F and partly cloudy Friday: 71°F and rainy Saturday: 77°F and sunny Sunday: 76°F and sunny Monday: 74°F and sunny
関数は返された値を拡張 JSONに自動的に直列化します。 これはタイプ情報を保持するには便利ですが、アプリケーションにとって例外的な処理である場合があります。
たとえば、次の関数から返されるオブジェクトの値は、構造化された EJSON 値に変換されます。
exports = function() { return { pi: 3.14159, today: new Date(), } }
{ "pi": { "$numberDouble": "3.14159" }, "today": { "$date": { "$numberLong": "1652297239913" } } }
値を標準的な JSON として返すために、値に対して JSON.stringify()
を呼び出すと、次のように文字列化された結果が返されます。
exports = function() { return JSON.stringify({ pi: 3.14159, today: new Date(), }) }
"{\"pi\":3.14159,\"today\":\"2022-05-11T19:27:32.207Z\"}"
ユーザー関数とシステム関数
関数を実行可能なコンテキストは、構成方法と呼び出し方法に応じて、次の 2 通りあります。
ユーザー関数はアプリケーションの特定のユーザーのコンテキストの枠内で実行されます。通常、特定のユーザーとは関数を呼び出したログイン ユーザーです。ユーザー関数には、ルールとスキーマ検証が適用されます。
システム関数は、特定のアプリケーション ユーザーでなく、システムユーザーとして実行されます。MongoDB CRUD と Aggregation API にフルアクセスでき、すべてのルールとスキーマの検証をバイパスします。
注意
動的な context.user 参照
context.user への参照は、関数を呼び出した認証ユーザーが常に解決先となります。この設定は、関数がシステム関数として実行される場合でも、認証ユーザーがいる限り変わりません。関数がシステム関数として実行されているかどうかを確認するには、context.runningAsSystem()
を呼び出します。
トリガーや Webhook における場合など、関数が認証ユーザーによって呼び出されることなく実行される場合は、動的参照によって id
または他の関連データを持たない システムユーザーが解決先となります。
関数の定義
App Services UI を使用するか、App Services CLI または GitHub 配置で関数の構成とソースコードをインポートすることで、関数をアプリケーションで作成、管理できます。
ユーザー認証の設定
Atlas App Services の関数は常に特定のアプリケーションユーザー配下で、またはルールをバイパスするシステムユーザーとして実行されます。関数の実行ユーザーを構成するには、Atlas App Services が使用する認証の種類を指定します。
認証タイプ | 説明 |
---|---|
アプリケーション認証 | このタイプの認証では、クライアント アプリケーションが関数を呼び出す時にログインした既存のアプリケーション ユーザー配下で関数を実行するように設定されます。関数が別の関数から呼び出された場合は、その関数から実行ユーザーを継承します。 |
システム | このタイプの認証では、MongoDB の CRUD および集計 API へのフルアクセス権を持ち、ルール、ロール、または権限の影響を受けないシステムユーザーとして関数を実行するように構成されます。 |
ユーザー ID | このタイプの認証では、常に特定のアプリケーション ユーザーとして関数が実行されるように設定されます。 |
スクリプト | このタイプの認証では、定義したカスタム関数の結果に基づいて決定された特定のアプリケーション ユーザーとして関数を実行するように構成されます。この関数は特定のユーザーの id 文字列を返す必要があります。または、 { "runAsSystem": true } を返すことでシステムユーザーを指定することもできます。 |
関数の実行ログの設定
デフォルトでは、Atlas App Services が関数を実行するたびに、関数が受け取った引数をログ エントリに含まれます。Atlas App Services が引数をログに記録しないようにするには、Log Function Arguments を無効にします。
関数のプライバシーレベルの設定
デフォルトで、クライアント アプリケーションから関数を呼び出すことも、同じアプリケーション内の他の関数を呼び出すこともできます。Private を true
に設定すると、クライアント アプリケーションからの関数の参照や呼び出しを防ぐことができます。
プライベート関数は引き続き、式やその他の関数(受信 Web フックや受信トリガーを含む)から呼び出すことができます。
関数コードの書込み
新規関数を作成して構成が終わったら、次は関数を呼び出すときに実行される JavaScript コードを書きます。関数エディターを使用して、Atlas App Services UI から直接コードを書くことができます。
注意
async/await、分割代入、およびテンプレートリテラルなど、ほとんどの最新のJavaScript(ES6以降)機能を関数で使用できます。
関数の Settings ページから以下の操作を行います。
[Function Editor] タブをクリックします。
関数に javascript コードを追加します。少なくとも、次の例のように、コードは
exports
に関数を割り当てる必要があります。exports = function() { return "Hello, world!"; };
関数のソースコードの記述
Atlas 関数は、個々のファイルからエクスポートする標準の JavaScript(ES6 以降)関数を実行します。functions
ディレクトリまたはそのサブディレクトリのいずれかに、関数と同じ名前の .js
ファイルを作成します。
touch functions/myFunction.js
Tip
functions
ディレクトリ内のネストされたフォルダー内で関数を定義できます。関数名の中にスラッシュを使うことで、その関数のディレクトリ パスを示します。
関数の .js
ファイルを作成したら、関数のソースコードを記述します。例:
exports = async function hello(...args) { // Write your function logic here! You can... // Import dependencies const assert = require("assert") assert(typeof args[0] === "string") // Use ES6+ syntax const sayHello = (name = "world") => { console.log(`Hello, ${name}.`) } // Return values back to clients or other functions return sayHello(args[0]) }
注意
async/await、分割代入、およびテンプレートリテラルなど、ほとんどの最新のJavaScript(ES6 以降)機能を関数で使用できます。Atlas App Services が特定の機能をサポートしているかどうかを確認するには、「JavaScript サポート」を参照してください。
機能の設定
アプリケーションの functions
ディレクトリで config.json
ファイルを開き、新規関数の構成オブジェクトを配列に追加します。オブジェクトは次の形式である必要があります。
{ "name": "<Function Name>", "private": <Boolean>, "can_evaluate": { <JSON Expression> }, "disable_arg_logs": <Boolean>, "run_as_system": <Boolean>, "run_as_user_id": "<App Services User ID>", "run_as_user_id_script_source": "<Function Source Code>" }
ユーザー認証の設定
Atlas App Services の関数は常に特定のアプリケーションユーザー配下で、またはシステムユーザー(ルールをバイパスする)として実行されます。関数の実行ユーザーを構成するには、Atlas App Services が使用する認証の種類を指定します。
システム
システムユーザーとして関数を実行するには、次の構成を使用します。
{ "run_as_system": true, "run_as_user_id": "", "run_as_user_id_script_source": "" } user
個別のユーザーとして関数を実行するには、次の構成を使用します。
{ "run_as_system": false, "run_as_user_id": "<App Services User Id>", "run_as_user_id_script_source": "" } スクリプト
関数を実行する 3 番目の方法は、ユーザー ID を返す別の関数を指定することです。関数はこのユーザーとして実行されます。これを行うには、次の構成を使用します。
{ "run_as_system": false, "run_as_user_id": "", "run_as_user_id_script_source": "<Function Source Code>" }
実行ログ取得の設定
関数が引数として受け取る値をログ エントリに含めるには、 disable_arg_logs
を false
に設定します。
承認式の指定
Can Evaluate 式を定義することで、各リクエストの内容に基づいてリクエストを動的に承認できます。Atlas App Services は、関数が呼び出されるたびに式を評価します。式を指定しない場合、Atlas App Services は認証されたすべての受信リクエストを自動的に承認します。
式は、%%request
および %%user
の展開を含む標準の式変数を展開できます。
例
次の式は、指定されたアドレスのリストに送信元の IP アドレスが含まれていない場合にのみ、受信リクエストを承認します。
{ "%%request.remoteIPAddress": { "$nin": [ "248.88.57.58", "19.241.23.116", "147.64.232.1" ] } }
関数のプライバシーレベルの設定
デフォルトで、クライアント アプリケーションから関数を呼び出すことも、同じアプリケーション内の他の関数を呼び出すこともできます。private
を true
に設定すると、クライアント アプリケーションからの関数の参照や呼び出しを防ぐことができます。
プライベート関数は、ルール式または別の関数(HTTPS endpoints や Atlas Triggers を含む)から呼び出すことができます。
関数の呼び出し
関数は、他の関数、接続済みのクライアント アプリケーション、または App Services CLI から呼び出すことができます。
このセクションの例では、2 つの引数を受け取り、それらを加算して結果を返す sum
という名前の単純な関数を呼び出す方法が示されています。
// sum: adds two numbers exports = function sum(a, b) { return a + b; };
関数からの呼び出し
関数は別の関数から呼び出すことができ、任意の関数でグローバル変数として使用可能な context.functions インターフェイスを使用します。主な例として、HTTPS endpoints、Atlas Triggers、GraphQL のカスタム リゾルバ(廃止予定、詳細はこちら)が挙げられます。呼び出された関数は、呼び出した関数と同じコンテキスト内で実行されます。
// difference: subtracts b from a using the sum function exports = function difference(a, b) { return context.functions.execute("sum", a, -1 * b); };
App Services CLI からの呼び出し
App Services CLI の function run コマンドも関数の呼び出しに使用できます。このコマンドは、関数の結果を EJSON として返すほか、ログやエラー メッセージも返します。
appservices function run \ --name=sum \ --args=1 --args=2
デフォルトでは、関数はシステム コンテキストで実行されます。特定のユーザーのコンテキストで関数を呼び出すには、--user
引数にそのユーザーのユーザー ID を含めます。
appservices function run \ --name=sum \ --args=1 --args=2 \ --user=61a50d82532cbd0de95c7c89
ルール式からの呼び出し
ルール式からも関数を呼び出すことができます。呼び出しに使用される %function
演算子は、評価の結果、関数の戻り値を出します。関数がエラーをスローした場合、式は false
と評価されます。
{ "numGamesPlayed": { "%function": { "name": "sum", "arguments": [ "%%root.numWins", "%%root.numLosses" ] } } }
Realm SDK からの呼び出し
重要
Atlas Functions を使用する際は、コード インジェクションから保護するために、クライアント データを必ずサニタイズしてください。
Realm SDK またはワイヤプロトコル経由で接続されるクライアント アプリケーションから関数を呼び出すことができます。クライアント アプリケーションから関数を呼び出す方法を示すコードの例については、次の Realm SDK のドキュメントを参照してください。
制約
関数の実行時間は、1 回のリクエストにつき 300 秒を上限とし、300 秒を過ぎるとタイムアウトして失敗します。
関数はある時点で最大 350 MB のメモリを使用する可能性があります。
関数の非同期操作には 1,000 回の上限が設けられています。
関数は、最もよく使用されている ES6+ 機能と Node.js 組み込みモジュールをサポートしています。ただし、サーバーレス ワークロードにとって一般的でないか適していない一部の機能はサポートされていません。詳細については、「JavaScript サポート」を参照してください。
受信リクエストの最大サイズは 18 MB に制限されています。この制限は、関数が HTTPS エンドポイント経由で呼び出される場合、関数に渡されるすべての引数の合計サイズと、リクエスト ヘッダーまたはペイロードに適用されます。