Atlas Functions
GraphQL 已弃用。了解详情。
Overview
Atlas Function 是一段服务器端 JavaScript 代码,您编写该代码来定义应用的行为。您可以直接从客户端应用调用应用的函数,也可以定义自动集成和调用函数的服务。
函数可以调用其他函数,并包含内置客户端,用于处理 MongoDB Atlas 集群中的数据。这些函数还包括有用的全局实用程序,支持常见的 Node.js 内置模块,并且可以从 npm 注册表中导入和使用外部包。
exports = function(name) { return `Hello, ${name ?? "stranger"}!` }
函数是无服务器性质的
调用函数时,应用程序会将请求路由到托管应用程序服务器,该服务器为代码求值并返回结果。此模型使函数具备无服务器性质,也即您不必部署和管理服务器来运行代码。您只需编写函数源代码,然后应用程序处理执行环境。
函数有上下文
函数会在反映其执行环境的上下文中运行。该上下文包括调用该函数的用户、如何进行调用以及调用该函数时应用的状态。您可以使用上下文来运行特定于用户的代码,并与应用的其他部分配合使用。
要了解有关如何使用函数上下文的详情,请参阅上下文。
何时使用函数
函数可以运行您定义的任意 JavaScript 代码,这意味着您几乎可以在任何情况下使用这些函数。常见使用案例包括低延迟、短时间运行的任务,如数据移动、转换和验证。您还可以使用它们连接外部服务,从客户端应用程序中抽象出实施细节。
除了直接调用的函数之外,您还可以为各种服务写入函数,例如HTTPS endpoints 、触发器和GraphQL自定义解析程序( GraphQL已弃用,学习;了解更多)。 这些服务会自动调用函数来处理特定事件。 示例,每当数据库trigger观察到变更事件时,它就会将该变更事件作为参数来调用关联的函数。 然后,您可以在trigger函数中访问权限变更事件的信息并做出适当响应。
如何编写函数
函数的代码本质上是一个已命名的JavaScript源文件,这意味着您可以在单个函数文件中定义多个JavaScript函数。 该文件必须导出单个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\"}"
用户和系统函数
函数可以在两个上下文中运行,具体取决于它们的配置和调用方式:
系统功能以系统用户而非特定应用程序用户的身份运行。系统函数可以完全访问 MongoDB CRUD 和 Aggregation API,并绕过所有规则和模式验证。
注意
动态 context.user 参考
对 context.user 的引用始终解析为调用函数的经过身份验证的用户(如果有),即使该函数作为系统函数运行亦是如此。要确定某个函数是否作为系统函数运行,请调用 context.runningAsSystem()
。
如果函数没有经过身份验证的用户调用即执行(例如在Trigger 或 Webhook 中),则动态引用将解析为没有 id
或其他关联数据的系统用户。
定义函数
您可以从 App Services 用户界面或通过使用 App Services CLI 或 GitHub 部署导入函数配置和源代码来创建和管理应用程序中的函数。
配置用户身份验证
App Services 中的函数始终在特定应用程序用户的上下文中执行,或作为绕过规则的系统用户执行。要配置函数的执行用户,请指定 App Services 应使用的身份验证类型。
身份验证类型 | 说明 |
---|---|
应用程序身份验证 | 这种类型的身份验证将函数配置为在客户端应用程序调用该函数时登录的现有应用程序用户的上下文中运行。如果已从另一个函数调用该函数,那么它将继承执行该函数的用户。 |
记录 | 这种类型的身份验证将函数配置为以系统用户身份运行,该用户对 MongoDB CRUD 和 Aggregation API 具有完全访问权限,并且不受任何规则、角色或权限的影响。 |
用户 ID | 这种类型的身份验证将函数配置为始终作为特定应用程序用户运行。 |
脚本 | 这种类型的身份验证将函数配置为作为特定应用程序用户运行,该用户根据您定义的自定义函数的结果确定。该函数必须返回特定用户的 id 字符串,或者可以通过返回 { "runAsSystem": true } 来指定系统用户。 |
配置函数执行日志
默认情况下,App Services 在每次执行函数的日志条目中包含函数收到的参数。如果要阻止 App Services 记录参数,请禁用 Log Function Arguments。
配置函数的隐私级别
默认情况下,您可以从客户端应用程序调用函数,也可以调用同一应用程序中的其他函数。您可以通过将 Private 设置为 true
来阻止客户端应用程序查看或调用函数。
您仍然可以从表达式和其他函数(包括传入的 webhook 和触发器)中调用私有函数。
编写函数源代码
Atlas Function运行标准 ES 6 + 您从单个文件导出的JavaScript函数。 在functions
目录或其子目录之一中创建与函数同名的.js
文件。
touch functions/myFunction.js
提示
您可以在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]) }
注意
您可以在函数中使用大多数现代 (ES 6 +) JavaScript功能,包括异步/等待、解构和模板字面量。 要查看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>" }
设置用户身份验证
App Services中的函数始终在特定应用程序用户的上下文中或作为系统用户(绕过规则)执行。 要配置函数的执行用户,请指定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": "" } 脚本
执行函数的第三种方法是指定另一个返回用户 ID 的函数。 您的函数将以该用户身份执行。 为此,请使用以下配置:
{ "run_as_system": false, "run_as_user_id": "", "run_as_user_id_script_source": "<Function Source Code>" }
设置执行日志记录
要在其日志条目中包含函数作为参数接收的任何值,请将disable_arg_logs
设立为false
。
配置函数的隐私级别
默认情况下,您可以从客户端应用程序调用函数,也可以调用同一应用程序中的其他函数。您可以通过将 private
设置为 true
来阻止客户端应用程序查看或调用函数。
您可以从规则表达式或其他函数中调用私有函数,包括HTTPS endpoints和触发器。
调用函数
您可以通过其他函数、连接的客户端应用程序或 App Services CLI 调用某个函数。
本部分中的示例演示了如何调用名为 sum
的简易函数,该函数可接受两个参数、添加这两个参数并返回结果:
// sum: adds two numbers exports = function sum(a, b) { return a + b; };
从函数调用
可以通过 context.functions 接口从一个函数调用另一个函数,该接口可可任何函数中用作全局变量。这包括 HTTPS 端点、触发器和 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
默认情况下,函数在系统上下文中运行。要在特定用户的上下文中调用函数,请将其用户 ID 纳入 --user
参数。
appservices function run \ --name=sum \ --args=1 --args=2 \ --user=61a50d82532cbd0de95c7c89
从规则表达式调用
可以使用 %function
操作符从规则表达式调用函数。该操作符可计算出函数的返回值。如果函数抛出错误,则表达式的计算结果为 false
{ "numGamesPlayed": { "%function": { "name": "sum", "arguments": [ "%%root.numWins", "%%root.numLosses" ] } } }
通过 Realm SDK 调用
重要
使用函数时,确保对客户端数据进行清理,以防止代码注入。
您可以从使用 Realm SDK 连接的客户端应用程序或通过传输协议来调用函数。有关演示如何从客户端应用程序调用函数的代码示例,请参阅 Realm SDK 的文档:
约束
每个请求的函数运行时间上限为 300 秒,之后函数将超时并失效。
函数可能随时使用高达350MB 的内存。
函数不能超过 1000 次异步操作。
函数支持最常用的 ES6+ 功能和 Node.js 内置模块,但不支持某些不常见或不适合无服务器工作负载的功能。有关详情,请参阅 JavaScript 支持。
使用 net 内置模块时,函数最多可打开 25 个套接字。
传入请求的最大大小限制为 18 MB。此限制适用于传递给函数的所有参数的总大小,以及以及任何请求标头或有效负载(如果通过 HTTPS 端点调用该函数)。