Funções do Atlas
Nesta página
O GraphQL está obsoleto. Saiba mais.
Visão geral
Uma função do Atlas é um código JavaScript do lado do servidor que você escreve para definir o comportamento de sua aplicação. Você pode chamar as funções do seu aplicativo diretamente de uma aplicação de cliente ou definir serviços que integram e chamam funções automaticamente.
As funções podem chamar outras funções e incluir um cliente integrado para trabalhar com dados em clusters MongoDB Atlas. Elas também incluem utilitários globais úteis, suportam módulos integrados comuns do Node.js e podem importar e usar pacotes externos do registro npm.
exports = function(name) { return `Hello, ${name ?? "stranger"}!` }
As funções são sem servidor
Quando uma função é chamada, seu aplicativo encaminha a solicitação para um servidor de aplicativos gerenciado que avalia seu código e retorna o resultado. Esse modelo torna as funções sem servidor, o que significa que você não precisa implantar e gerenciar um servidor para executar o código. Em vez disso, você escreve o código-fonte da função e seu aplicativo lida com o ambiente de execução.
Funções têm contexto
Uma função é executada em um contexto que reflete seu ambiente de execução. O contexto inclui o usuário que chamou a função, como ele a chamou e o estado de sua aplicação quando a chamou. Você pode usar o contexto para executar código específico do usuário e trabalhar com outras partes de sua aplicação.
Para saber mais sobre como trabalhar com o contexto da função, consulte Contexto.
Quando usar as funções
As funções podem executar código JavaScript arbitrário definido por você, o que significa que você pode usá-las para quase tudo. Os casos de uso comuns incluem tarefas de baixa latência e execução curta, como movimentação de dados, transformações e validação. Você também pode usá-los para se conectar a serviços externos e abstrair os detalhes de implementação dos aplicativos clientes.
Além das funções que você invoca diretamente, você também escreve funções para vários serviços, como HTTPS endpoints, Triggers e resolvedores personalizados GraphQL (GraphQL está obsoleto, saiba mais). Esses serviços chamam automaticamente as funções para lidar com eventos específicos. Por exemplo, sempre que um gatilho de trigger de banco de dados ) observa um evento de alteração, ele chama sua função associada com o evento de alteração como argumento. Na função de trigger, é possível acessar as informações do evento de modificação e responder adequadamente.
Dica
Veja também:
Como escrever uma função
O código de uma função é essencialmente um arquivo de código fonte JavaScript nomeado, o que significa que você pode definir várias funções JavaScript em um único arquivo de função. O arquivo deve exportar uma única função JavaScript para servir como ponto de entrada das chamadas recebidas. Quando você chama uma função por nome, você está realmente chamando a função JavaScript atribuída a exports
no arquivo de origem da função.
Por exemplo, aqui está uma função simples que aceita um argumento name
, adiciona uma mensagem de registro e retorna uma saudação para o nome fornecido:
exports = function Hello(name) { console.log(`Said hello to ${name}`); return `Hello, ${name}!`; };
Você pode usar a sintaxe JavaScript moderna e importar pacotes para definir funções mais complexas:
// 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
As funções serializam automaticamente os valores retornados para JSON estendido. Isto é útil para preservar informações de tipo, mas pode não ser o que seu aplicação espera.
Por exemplo, os valores no objeto retornado da seguinte função são convertidos em valores EJSON estruturados:
exports = function() { return { pi: 3.14159, today: new Date(), } }
{ "pi": { "$numberDouble": "3.14159" }, "today": { "$date": { "$numberLong": "1652297239913" } } }
Para retornar um valor como JSON padrão, chame JSON.stringify()
no valor e, em seguida, retorne o resultado em string:
exports = function() { return JSON.stringify({ pi: 3.14159, today: new Date(), }) }
"{\"pi\":3.14159,\"today\":\"2022-05-11T19:27:32.207Z\"}"
Funções do usuário e do sistema
Uma função pode ser executada em dois contextos, dependendo de como eles são configurados e chamados:
Uma função de usuário é executada no contexto de um usuário específico do seu aplicativo. Normalmente, esse é o usuário conectado que chamou a função. As funções do usuário estão sujeitas às regras e à validação do esquema.
Uma função do sistema é executada como o usuário do sistema em vez de um usuário específico do aplicativo. As funções do sistema têm acesso total às APIs CRUD e de aggregation do MongoDB e ignoram todas as regras e a validação de esquema.
Observação
Referências context.user dinâmicas
As referências a context.user sempre são resolvidas para o usuário autenticado que chamou uma função, se houver um, mesmo que a função seja executada como uma função do sistema. Para determinar se uma função está sendo executada como uma função do sistema, chame context.runningAsSystem()
.
Se uma função for executada sem ser chamada por um usuário autenticado, como em um trigger ou webhook, as referências dinâmicas serão resolvidas para o usuário do sistema que não tem id
ou outros dados associados.
Definir uma função
Você pode criar e gerenciar funções em seu aplicativo a partir da UI do App Services ou importando a configuração da função e o código fonte com App Services CLI ou sistema GitHub.
Nomear a nova função
Insira um nome de identificação exclusivo para a função no campo Name. Esse nome deve ser distinto de todas as outras funções do aplicativo.
Dica
Você pode definir funções dentro de pastas agrupadas. Os nomes de função são caminhos separados por barra, então, uma função denominada utils/add
mapeia para functions/utils/add.js
nos arquivos de configuração da aplicação.
Configurar autenticação de usuário
As funções no App Services sempre são executadas no contexto de um usuário específico do aplicativo ou como um usuário do sistema que ignora as regras. Para configurar o usuário de execução da função, especifique o tipo de autenticação que o App Services deve usar.
Tipo de autenticação | Descrição |
---|---|
Autenticação de aplicativos | Esse tipo de autenticação configura uma função para ser executada no contexto do usuário do aplicativo existente que estava logado quando o aplicativo cliente chamou a função. Se a função foi chamada de outra função, ela herda o usuário de execução dessa função. |
Sistema | Esse tipo de autenticação configura uma função para ser executada como um usuário do sistema que tem acesso total às APIs de Agregação e CRUD do MongoDB e não é afetada por nenhuma regra, função ou permissão. |
ID do usuário | Este tipo de autenticação configura uma função para sempre executar
como um usuário de aplicativo específico. |
Roteiro | Esse tipo de autenticação configura uma função para ser executada como um usuário de aplicativo específico, determinado com base no resultado de uma função personalizada que você define. A função precisa retornar uma string id de um usuário específico ou pode especificar um usuário do sistema ao retornar { "runAsSystem": true } . |
Configurar registros de execuções da função
Por padrão, o App Services inclui os argumentos que uma função recebeu na entrada de registro para cada execução da função. Se quiser impedir que o App Services registre os argumentos, desabilite Log Function Arguments.
Especificar uma expressão de autorização
Você pode autorizar solicitações de forma dinâmica com base nos conteúdos de cada solicitação ao definir uma expressão Can Evaluate. O App Services avalia a expressão sempre que a função é chamada. Se você não especificar uma expressão, o App Services autorizará automaticamente todas as solicitações de entrada autenticadas.
A expressão pode expandir variáveis de expressão padrão, incluindo as expansões %%request
e %%user
.
Configurar o nível de privacidade da função
Por padrão, você pode chamar uma função de aplicativos de clientes, bem como outras funções no mesmo aplicativo. Você pode impedir que aplicativos de clientes vejam ou chamem uma função definindo Private como true
.
Você ainda pode chamar uma função privada de expressão e outras funções, incluindo webhooks e gatilhos recebidos.
Escrever o código da função
Depois de criar e configurar a nova função, é hora de escrever o código JavaScript que será executado quando você chamar a função. Você pode escrever o código diretamente na UI do App Services usando o editor de função.
Observação
Você pode usar as funcionalidades JavaScript mais modernas (ES6+) em funções, incluindo async/await, desestruturação e literais de modelo.
Na página Settings da função:
Clique na aba Function Editor.
Adicione o código javascript à função. No mínimo, o código deve atribuir uma função a
exports
, como no seguinte exemplo:exports = function() { return "Hello, world!"; };
Escreva o código fonte da função
As Atlas Functions executam funções ES6+ JavaScript padrão que você exporta de arquivos individuais. Crie um arquivo .js
com o mesmo nome da função no diretório functions
ou em um de seus subdiretórios.
touch functions/myFunction.js
Dica
Você pode definir funções dentro de pastas aninhadas no diretório functions
. Use barras em um nome de função para indicar seu caminho de diretório.
Depois de criar o arquivo .js
da função, escreva o código-fonte da função, por exemplo:
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]) }
Observação
Você pode usar os recursos JavaScript mais modernos (ES6+) em funções, incluindo async/await, desestruturação e literais de modelo. Para ver se o App Services oferece suporte a uma funcionalidade específica, consulte Suporte a JavaScript.
Configurar a função
No diretório functions
do seu aplicação, abra o arquivo config.json
e adicione um objeto de configuração para sua nova função à array. O objeto deve ter o seguinte formato:
{ "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>" }
Definir autenticação de usuário
As funções no App Services sempre são executadas no contexto de um usuário específico do aplicação ou como usuário do sistema (o que ignora as regras). Para configurar o usuário de execução da função, especifique o tipo de autenticação que o App Services deve usar:
Sistema
Para executar uma função como usuário do sistema, use a seguinte configuração:
{ "run_as_system": true, "run_as_user_id": "", "run_as_user_id_script_source": "" } Usuário
Para executar uma função como um usuário específico, use a seguinte configuração:
{ "run_as_system": false, "run_as_user_id": "<App Services User Id>", "run_as_user_id_script_source": "" } Roteiro
A terceira maneira de executar uma função é especificar outra função que retorna um ID de usuário. Sua função será executada como este usuário. Para fazer isso, use a seguinte configuração:
{ "run_as_system": false, "run_as_user_id": "", "run_as_user_id_script_source": "<Function Source Code>" }
Definir registro de execução
Para incluir quaisquer valores que a função receber como argumentos em sua entrada de registro, defina disable_arg_logs
como false
.
Especificar uma expressão de autorização
Você pode autorizar solicitações de forma dinâmica com base nos conteúdos de cada solicitação ao definir uma expressão Can Evaluate. O App Services avalia a expressão sempre que a função é chamada. Se você não especificar uma expressão, o App Services autorizará automaticamente todas as solicitações de entrada autenticadas.
A expressão pode expandir variáveis de expressão padrão, incluindo as expansões %%request
e %%user
.
Exemplo
A expressão seguinte só autoriza solicitações recebidas se o endereço IP do remetente não estiver incluído na lista de endereços especificada.
{ "%%request.remoteIPAddress": { "$nin": [ "248.88.57.58", "19.241.23.116", "147.64.232.1" ] } }
Configurar o nível de privacidade da função
Por padrão, você pode chamar uma função de aplicativos de clientes, bem como outras funções no mesmo aplicativo. Você pode impedir que aplicativos de clientes vejam ou chamem uma função definindo private
como true
.
Você pode chamar uma função privada de uma expressão de regra ou outra função, incluindo HTTPS endpoints .
Chamar uma função
Você pode chamar uma função de outras funções, de um aplicativo cliente conectado ou com o App Services CLI.
Os exemplos nesta seção demonstram a chamada de uma função simples denominada sum
que recebe dois argumentos, os adiciona e retorna o resultado:
// sum: adds two numbers exports = function sum(a, b) { return a + b; };
Chamar de uma função
Você pode chamar uma função de outra função por meio da interface context.functions , que está disponível como uma variável global em qualquer função. Isso inclui HTTPS endpoints, Atlas Triggers e resolvedores personalizados GraphQL (descontinuados, saiba mais). A função chamada é executada no mesmo contexto da função que a chamou.
// difference: subtracts b from a using the sum function exports = function difference(a, b) { return context.functions.execute("sum", a, -1 * b); };
Chamada do App Services CLI
Você pode chamar uma função por meio da App Services CLI com o comando execução de função. O comando retorna o resultado da função como EJSON, bem como quaisquer mensagens de registro ou de erro.
appservices function run \ --name=sum \ --args=1 --args=2
Por padrão, as funções são executadas no contexto do sistema . Para chamar uma função no contexto de um usuário específico, inclua seu ID de usuário no argumento --user
.
appservices function run \ --name=sum \ --args=1 --args=2 \ --user=61a50d82532cbd0de95c7c89
Chamada de expressões de regras
Você pode chamar uma função de uma expressão de regra usando o operador %function
. O operador avalia o valor de retorno da função. Se a função gerar um erro, a expressão será avaliada como false
.
{ "numGamesPlayed": { "%function": { "name": "sum", "arguments": [ "%%root.numWins", "%%root.numLosses" ] } } }
Chamada de Realm SDK
Importante
Certifique-se de limpar os dados do cliente para se proteger contra a injeção de código ao usar funções.
Você pode chamar uma função de aplicativos clientes que estão conectados com um Realm SDK ou através do protocolo de fio. Para exemplos de código que demonstram como chamar uma função de um aplicativo cliente, consulte a documentação para os Realm SDKs:
Restrições
As funções são limitadas a 300 segundos de tempo de execução por solicitação, após o qual uma função atingirá o tempo limite e falhará.
As funções podem usar até 350 MB de memória a qualquer momento.
As funções estão limitadas a 1000 operações assíncronas.
As funções suportam as funcionalidades ES6+ mais comumente usadas e módulos integrados do Node.js. No entanto, algumas funcionalidades incomuns ou inadequadas para cargas de trabalho sem servidor não são suportadas. Para obter mais informações, consulte Suporte a JavaScript.
Uma função pode abrir um máximo de 25 soquetes usando o módulo interno dede rede.
As solicitações recebidas são limitadas a um tamanho máximo de 18 MB. Esse limite se aplica ao tamanho total de todos os argumentos passados para a função, bem como qualquer cabeçalho de solicitação ou carga útil se a função for chamada por meio de um ponto de conexão HTTPS.