Docs Home → Atlas App Services
Atlas Functions
On this page
Overview
An Atlas Function is a piece of server-side JavaScript code that you write to define your app's behavior. You can call your app's functions directly from a client app or define services that integrate and call functions automatically.
Functions can call other functions and include a built-in client for working with data in MongoDB Atlas clusters. They also include helpful global utilities, support common Node.js built-in modules, and can import and use external packages from the npm registry.
exports = function(name) { return `Hello, ${name ?? "stranger"}!` }
Functions are Serverless
When a function is called, your app routes the request to a managed app server that evaluates your code and returns the result. This model makes functions serverless, which means that you don't have to deploy and manage a server to run the code. Instead, you write the function source code and your app handles the execution environment.
Functions have Context
A function runs in a context that reflects its execution environment. The context includes the user that called the function, how they called it, and the state of your app when they called it. You can use context to run user-specific code and work with other parts of your app.
To learn more about how to work with function context, see Context.
When To Use Functions
Functions can run arbitrary JavaScript code that you define, which means you can use them for almost anything. Common use cases include low-latency, short-running tasks like data movement, transformations, and validation. You can also use them to connect to external services and abstract away implementation details from your client applications.
In addition to functions that you invoke directly, you also write functions for various services like HTTPS Endpoints, Triggers, and GraphQL custom resolvers. These services automatically call functions to handle specific events. For example, whenever a database trigger observes a change event it calls its associated function with the change event as an argument. In the trigger function, you can then access information from the change event and respond appropriately.
How to Write a Function
The code for a function is essentially a named JavaScript source file,
which means you can define multiple JavaScript functions in a single
function file. The file must export a single JavaScript function from to
serve as the entrypoint for incoming calls. When you call a function by
name, you're actually calling the JavaScript function assigned to
exports
in the function's source file.
For example, here's a simple function that accepts a name
argument,
adds a log message, and returns a greeting for the provided name:
exports = function Hello(name) { console.log(`Said hello to ${name}`); return `Hello, ${name}!`; };
You can use modern JavaScript syntax and import packages to define more complex functions:
// 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
Functions automatically serialize returned values to Extended JSON. This is useful to preserve type information but may not be what your application expects.
For example, the values in the object returned from the following function are converted into structured EJSON values:
exports = function() { return { pi: 3.14159, today: new Date(), } }
{ "pi": { "$numberDouble": "3.14159" }, "today": { "$date": { "$numberLong": "1652297239913" } } }
To return a value as standard JSON, call JSON.stringify()
on the
value and then return the stringified result:
exports = function() { return JSON.stringify({ pi: 3.14159, today: new Date(), }) }
"{\"pi\":3.14159,\"today\":\"2022-05-11T19:27:32.207Z\"}"
User and System Functions
A function can run in two contexts depending on how they're configured and called:
A user function runs in the context of a specific user of your application. Typically this is the logged in user that called the function. User functions are subject to rules and schema validation.
A system function runs as the system user instead of a specific application user. System functions have full access to MongoDB CRUD and Aggregation APIs and bypass all rules and schema validation.
Note
Dynamic context.user references
References to context.user always resolve to
the authenticated user that called a function if there was one, even
if the function runs as a system function. To determine if a function
is running as a system function, call context.runningAsSystem()
.
If a function executes without being called by an authenticated user,
such as in a trigger or webhook, then dynamic references resolve to
the system user which has no id
or other
associated data.
Define a Function
You can create and manage functions in your application from the App Services UI or by importing the function configuration and source code with App Services CLI or GitHub deployment.
Call a Function
You can call a function from other functions, from a connected client application, or with App Services CLI.
The examples in this section demonstrate calling a simple function named
sum
that takes two arguments, adds them, and returns the result:
// sum: adds two numbers exports = function sum(a, b) { return a + b; };
Call from a Function
You can call a function from another function through the context.functions interface, which is available as a global variable in any function. This include HTTPS endpoints, triggers, and GraphQL customer resolvers. The called function runs in the same context as the function that called it.
// difference: subtracts b from a using the sum function exports = function difference(a, b) { return context.functions.execute("sum", a, -1 * b); };
Call from App Services CLI
You can call a function through App Services CLI with the function run command. The command returns the function result as EJSON as well as any log or error messages.
appservices function run \ --function=sum \ --args=1 --args=2
By default, functions run in the system context. To call a function in the context of a specific
user, include their User ID in the --user
argument.
appservices function run \ --function=sum \ --args=1 --args=2 \ --user=61a50d82532cbd0de95c7c89
Call from Rule Expressions
You can call a function from a rule expression by
using the %function
operator. The operator evaluates to
the return value of the function. If the function throws an error, the
expression evaluates to false
.
{ "numGamesPlayed": { "%function": { "name": "sum", "arguments": [ "%%root.numWins", "%%root.numLosses" ] } } }
Call from Realm SDKs
Important
Make sure to sanitize client data to protect against code injection when using Functions.
You can call a function from client applications that are connected with a Realm SDK or over the wire protocol. For code examples that demonstrate how to call a function from a client application, see the documentation for the Realm SDKs:
Constraints
Functions are capped at 300 seconds of runtime per request, after which a function will time out and fail.
Functions may use up to 256MB of memory at any time.
Functions are limited to 1000 async operations.
Functions support most commonly used ES6+ features and Node.js built-in modules. However, some features that are uncommon or unsuited to serverless workloads are not supported. For more information, see JavaScript Support.
A function may open a maximum of 25 sockets using the net built-in module.
Incoming requests are limited to a maximum size of 18 MB. This limit applies to the total size of all arguments passed to the function as well as any request headers or payload if the function is called through an HTTPS endpoint.