Guia de atualização do SDK do Firebase para Cloud Functions: da versão Beta à 1.0 ou posterior

Algumas mudanças importantes na API foram apresentadas na versão 1.0.0 do SDK do Firebase para Cloud Functions. A alteração principal, representada pela substituição do formato event.data por parâmetros de data e context, afeta todas as funções assíncronas (não HTTP). O SDK atualizado também pode ser usado com o firebase-functions-test, um SDK complementar para teste de unidade. Consulte Funções de teste de unidade para mais informações.

A versão 2.0.0 do SDK do Firebase para Cloud Functions apresentou uma alteração importante nos carimbos de data/hora em funções acionadas pelo Firestore.

Para atualizar os SDKs para a versão mais recente, execute o seguinte comando na pasta de funções:

npm install firebase-functions@latest --save
npm install firebase-admin@latest --save-exact

Também é preciso atualizar a Firebase CLI para a versão mais recente:

npm install -g firebase-tools

Alterações do SDK que afetam todas as funções assíncronas (não HTTP)

Alterações do SDK por tipo de acionador

Referências de API novas e legadas

Alterações na emulação de funções

Alterações do SDK que afetam todas as funções em segundo plano (não HTTP)

Divisão de parâmetros de eventos em dados e contexto

O uso do parâmetro event para funções assíncronas foi suspenso a partir da versão 1.0 do SDK do Firebase para Cloud Functions. Ele foi substituído por dois novos parâmetros: data e context.

O parâmetro data representa os dados que acionaram a função. Os campos do parâmetro data são determinados pelo tipo de acionador e variam de acordo com ele. Por exemplo, para o Realtime Database, o parâmetro data é um DataSnapshot. Veja as alterações por tipo de acionador para mais informações sobre o parâmetro data.

O parâmetro context fornece informações sobre a execução da função. Idêntico em todos os tipos de funções assíncronas, o context contém os campos eventId, timestamp, eventType, resource e params. Além disso, as funções do Realtime Database fornecem informações de autenticação ao usuário que acionou a função. Segue um exemplo de campos de contexto definidos em uma função acionada por uma gravação no Realtime Database:

exports.dbWrite = functions.database.ref('/path/with/{id}').onWrite((data, context) => {
  const authVar = context.auth; // Auth information for the user.
  const authType = context.authType; // Permissions level for the user.
  const pathId = context.params.id; // The ID in the Path.
  const eventId = context.eventId; // A unique event ID.
  const timestamp = context.timestamp; // The timestamp at which the event happened.
  const eventType = context.eventType; // The type of the event that triggered this function.
  const resource = context.resource; // The resource which triggered the event.
  // ...
});

Nova sintaxe de inicialização para firebase-admin

O firebase-admin agora é inicializado sem nenhum parâmetro no tempo de execução do Cloud Functions.

Versão v0.9.1 e anteriores

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

Versão v1.0.0 e posteriores

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

Não é mais possível transmitir em functions.config().firebase ao inicializar. Consulte a seção a seguir para mais detalhes sobre como acessar a configuração na v1.0.0.

Remoção de functions.config().firebase

functions.config().firebase foi removido. Se você quiser acessar os valores de configuração do seu projeto do Firebase, use process.env.FIREBASE_CONFIG:

let firebaseConfig = JSON.parse(process.env.FIREBASE_CONFIG);
/* {  databaseURL: 'https://databaseName.firebaseio.com',
       storageBucket: 'projectId.appspot.com',
       projectId: 'projectId' }
*/

Alterações do SDK por tipo de acionador

Para muitos acionadores de função compatíveis, a versão 1.0 apresenta alterações nos nomes de campos e métodos de dados. Veja nesta seção uma lista por tipo de acionador.

Realtime Database

Dados do evento agora como DataSnapshot

Em versões anteriores, event.data era um DeltaSnapshot. Agora na v 1.0 é um DataSnapshot.

Para os eventos onWrite e onUpdate, o parâmetro de dados tem campos before e after. Cada um deles é um DataSnapshot com os mesmos métodos disponíveis no admin.database.DataSnapshot. Por exemplo:

Versão v0.9.1 e anteriores

exports.dbWrite = functions.database.ref('/path').onWrite((event) => {
  const beforeData = event.data.previous.val(); // data before the write
  const afterData = event.data.val(); // data after the write
});

Versão v1.0.0 e posteriores

exports.dbWrite = functions.database.ref('/path').onWrite((change, context) => {
  const beforeData = change.before.val(); // data before the write
  const afterData = change.after.val(); // data after the write
});

Para onCreate, o parâmetro de dados é um DataSnapshot que representa os dados que acabaram de ser adicionados:

Versão v0.9.1 e anteriores

exports.dbCreate = functions.database.ref('/path').onCreate((event) => {
  const createdData = event.data.val(); // data that was created
});

Versão v1.0.0 e posteriores

exports.dbCreate = functions.database.ref('/path').onCreate((snap, context) => {
  const createdData = snap.val(); // data that was created
});

Para onDelete, o parâmetro de dados é um DataSnapshot representando os dados que acabaram de ser excluídos:

Versão v0.9.1 e anteriores

exports.dbDelete = functions.database.ref('/path').onDelete((event) => {
  const deletedData = event.data.previous.val(); // data that was deleted
});

Versão v1.0.0 e posteriores

exports.dbDelete = functions.database.ref('/path').onDelete((snap, context) => {
  const deletedData = snap.val(); // data that was deleted
});

Novas propriedades para informações de autenticação de usuário

Com o EventContext.auth v1.0.0, são inseridas duas novas propriedades para acessar as informações, incluindo as permissões, do usuário que acionou uma função.

  • EventContext.auth. Contém informações como uid e token de autenticação de usuários autenticados.
  • EventContext.authType. Contém níveis de permissão, o que permite detectar se o usuário é um usuário administrador, por exemplo.

Os desenvolvedores que usam campos event.auth não documentados devem atualizar todos códigos relacionados para usar essas novas propriedades.

Substituição de adminRef por ref

A referência .adminRef foi substituída pela referência .ref, que agora está autorizada com privilégios de administrador. Não há mais compatibilidade para o uso anterior de .ref, ou seja, como uma referência à alteração autorizada como o usuário que acionou a mudança.

Versão v0.9.1 e anteriores

exports.dbCreate = functions.database.ref('/path/{uid}').onCreate((event) => {
  const parentRef = event.data.adminRef.parent; // The Database reference to the parent authorized with admin privileges.

  const parentRefAsUser = event.data.ref.parent; // The Database reference to the parent authorized as the user which triggered the change.
});

Versão v1.0.0 e posteriores

exports.dbCreate = functions.database.ref('/path/{uid}').onCreate((snap, context) => {
  const parentRef = snap.ref.parent; // The Database reference to the parent authorized with admin privileges
});

Você ainda pode aplicar alterações autorizadas pelo usuário no Realtime Database usando o SDK Admin:

const functions = require('firebase-functions');
const admin = require('firebase-admin');

exports.impersonateMakeUpperCase = functions.database.ref('/messages/{pushId}/original')
    .onCreate((snap, context) => {
      const appOptions = JSON.parse(process.env.FIREBASE_CONFIG);
      appOptions.databaseAuthVariableOverride = context.auth;
      const app = admin.initializeApp(appOptions, 'app');
      const uppercase = snap.val().toUpperCase();
      const ref = snap.ref.parent.child('uppercase');

      const deleteApp = () => app.delete().catch(() => null);

      return app.database().ref(ref).set(uppercase).then(res => {
        // Deleting the app is necessary for preventing concurrency leaks
        return deleteApp().then(() => res);
      }).catch(err => {
        return deleteApp().then(() => Promise.reject(err));
      });
    });

Cloud Firestore

Assim como as alterações da v 1.0 do Realtime Database, onWrite e onUpdate têm um parâmetro de dados com campos before e after. Os eventos para onCreate e onDelete têm um parâmetro de dados que é um DocumentSnapshot do Cloud Firestore.

Versão v0.9.1 e anteriores

exports.dbWrite = functions.firestore.document('/doc/path').onWrite((event) => {
  const beforeData = event.data.previous.data(); // data before the write
  const afterData = event.data.data(); // data after the write
});

Versão v1.0.0 e posteriores

exports.dbWrite = functions.firestore.document('/doc/path').onWrite((change, context) => {
  const beforeData = change.before.data(); // data before the write
  const afterData = change.after.data(); // data after the write
});

Os eventos onCreate e onDelete têm um parâmetro de dados que é um DocumentSnapshot.

Versão v0.9.1 e anteriores

exports.dbDelete = functions.firestore.document('/doc/path').onDelete((event) => {
  const deletedData = event.data.previous.data(); // data that was deleted
});

Versão v1.0.0 e posteriores

exports.dbDelete = functions.firestore.document('/doc/path').onDelete((snap, context) => {
  const deletedData = snap.data(); // data that was deleted
});

Mudança importante na v2.0.0 para carimbos de data/hora do Firestore

A partir da v2.0.0 do SDK do Firebase para Cloud Functions, os valores de carimbo de data/hora em um instantâneo do Firestore recebido dentro de uma função são objetos de carimbo de data/hora do Firestore. Isso se aplica a snapshot.createTime, snapshot.updateTime, snapshot.readTime e qualquer valor de carimbo de data/hora em snapshot.data().

Versão v2.0.0 ou posteriores

exports.dbCreate = functions.firestore.document('/doc/path').onCreate((snap, context) => {
  //seconds of UTC time since Unix epoch
  console.log(snap.createTime.seconds);

  //fractions of a second at nanosecond resolution, 0 to 999,999,999
  console.log(snap.createTime.nanoseconds);
});

Autenticação

Em versões anteriores, event.data.metadata continha os campos obsoletos createdAt e lastSignedInAt. A versão 1.0 remove esses campos completamente e os substitui pelos campos creationTime e lastSignInTime no parâmetro userRecord.metadata.

Versão v0.9.1 e anteriores

// This code won't work with Cloud Functions SDK 1.0 and higher!
exports.authAction = functions.auth.user().onCreate((event) => {
  const userMetadata = event.data.metadata;

  const creationTime = userMetadata.createdAt; // 2016-12-15T19:37:37.059Z
  const lastSignInTime = userMetadata.lastSignedInAt; // 2018-01-03T16:23:12.051Z
}

Versão v1.0.0 e posteriores

exports.authAction = functions.auth.user().onCreate((userRecord, context) => {
  const creationTime = userRecord.metadata.creationTime; // 2016-12-15T19:37:37.059Z
  const lastSignInTime = userRecord.metadata.lastSignInTime; // 2018-01-03T16:23:12.051Z
}

Crashlytics

Na v 1.0, o manipulador de eventos que dispara sempre que ocorre um novo problema é onNew. O manipulador anterior chamado onNewDetected foi removido.

Versão v0.9.1 e anteriores

exports.newIssue = functions.crashlytics.issue().onNewDetected((event) => {
  const issue = event.data;

  const issueId = issue.issueId;
  const issueTitle = issue.issueTitle;
  const appName = issue.appInfo.appName;
  const appId = issue.appInfo.appId;
  const appPlatform = issue.appInfo.appPlatform;
  const latestAppVersion = issue.appInfo.latestAppVersion;
  const createTime = issue.createTime;
}

Versão v1.0.0 e posteriores

exports.newIssue = functions.crashlytics.issue().onNew((issue, context) => {
  const issueId = issue.issueId;
  const issueTitle = issue.issueTitle;
  const appName = issue.appInfo.appName;
  const appId = issue.appInfo.appId;
  const appPlatform = issue.appInfo.appPlatform;
  const latestAppVersion = issue.appInfo.latestAppVersion;
  const createTime = issue.createTime;
}

Armazenamento

O manipulador de eventos onChange foi removido. Em vez dele, o v 1.0 oferece compatibilidade para estes eventos:

  • onArchive: enviado apenas depois que o controle de versão do objeto é ativado no intervalo. Esse evento indica que a versão ativa de um objeto se tornou uma versão arquivada por ter sido arquivada ou substituída pelo upload de um objeto do mesmo nome.
  • onDelete: enviado quando um objeto é excluído permanentemente. Isso inclui objetos que são substituídos ou são excluídos como parte da configuração do ciclo de vida do intervalo. Para intervalos com o controle de versão do objeto ativado, esse tipo de evento não é enviado com o arquivamento de um objeto (consulte onArchive), mesmo que ele ocorra por meio do método storage.objects.delete.
  • onFinalize: enviado quando um novo objeto ou nova geração de um objeto existente é criada com sucesso no intervalo. Isso inclui a cópia ou regravação de um objeto existente. Um upload com falha não aciona esse evento.
  • onMetadataUpdate: enviado quando os metadados de um objeto existente são alterados.

Versão v0.9.1 e anteriores

exports.processFile = functions.storage.object().onChange((event) => {
  const object = event.data;

  const filePath = object.name; // Path of the File
  const contentType = object.contentType; // Mime type of the file

  // Exit if this is a deletion event.
  if (object.resourceState === 'not_exists') {
    console.log('This file was deleted.');
    return null;
  }

  // Exit if file exists but is not new and is only being triggered
  // because of a metadata change.
  if (resourceState === 'exists' && metageneration > 1) {
    console.log('This is a metadata change event.');
    return null;
  }

  // ...
}

Versão v1.0.0 e posteriores

exports.processFile = functions.storage.object().onFinalize((object, context) => {
  const filePath = object.name; // Path of the File
  const contentType = object.contentType; // Mime type of the file

  // ...
}

exports.fileDeleted = functions.storage.object().onDelete((object, context) => {
  console.log('This file was deleted.');
}

exports.metadataUpdated = functions.storage.object().onMetadataUpdate((object, context) => {
  console.log('This is a metadata change event.');
}

Pub/Sub

Como o tipo de acionador subjacente foi alterado, você precisa renomear e reimplantar as funções do Cloud Pub/Sub. Não é necessária nenhuma alteração no código da função.

Para atualizar as funções do Cloud Pub/Sub, siga estas etapas:

  1. Renomeie a função. Por exemplo, renomeie "myPubSubFunction" para "myNewPubSubFunction".
  2. Implante apenas essa função usando uma implantação parcial:

    firebase deploy --only functions:myNewPubSubFunction

  3. Após implantar "myNewPubSubFunction", exclua a função obsoleta anterior à versão 1.0.0 implantando todas as funções:

    firebase deploy --only functions

Durante o breve período entre esses comandos de implantação, você pode receber acionadores duplicados. Para lidar com este caso e para garantir o funcionamento normal, escreva funções idempotentes.

Referências de API novas e legadas

Para saber mais, consulte a referência da API para firebase-functions v1.0.0. Você também pode consultar a referência da API da v0.9.1 para ajudar na atualização.

Alterações na emulação de funções

  • firebase serve agora serve hospedagem e funções HTTP por padrão.
  • firebase experimental:functions:shell, que emula todas as funções, foi renomeada como firebase functions:shell.

Mudanças de sintaxe para o shell de funções

A sintaxe para chamar funções por meio do shell de funções foi atualizada para refletir a sintaxe para o firebase-functions v1.0.0.

// Inside functions shell

// To emulate database writes done by an administrative user:
myDbFunction(‘data’)

// To emulate database writes done by an authenticated user:
myDbFunction(‘data’, { auth: { uid: ‘abc’ }})

// To emulate database writes done by an unauthenticated user:
myDbFunction(‘data’, { authMode: ‘UNAUTHENTICATED’)

Enviar comentários sobre…

Precisa de ajuda? Acesse nossa página de suporte.