Protocolo de especificação para https.onCall

Um gatilho https.onCall do Cloud Functions é um gatilho HTTPS com um formato específico para a solicitação e a resposta. Veja nesta seção uma especificação para os formatos de solicitação e resposta HTTPS usados pelos SDKs do cliente para implementar a API. Essas informações podem ser úteis se os requisitos não puderem ser atendidos com os SDKs para Android, plataformas da Apple ou Web.

Formato de solicitação: cabeçalhos

A solicitação HTTP para um ponto de extremidade de acionamento chamável precisa ser um POST com os seguintes cabeçalhos:

  • Obrigatório: Content-Type: application/json
    • Um ; charset=utf-8 opcional é permitido.
  • Opcional: Authorization: Bearer <token>
    • Um token de ID de usuário do Firebase Authentication para o usuário conectado que faz a solicitação. O back-end verifica automaticamente esse token e o disponibiliza no context do gerenciador. Se o token não for válido, a solicitação será rejeitada.
  • Opcional: Firebase-Instance-ID-Token: <iid>
    • O token de registro do FCM do SDK do cliente do Firebase. Precisa ser uma string. Disponível no context do gerenciador. É usado para segmentar notificações push.
  • Opcional: X-Firebase-AppCheck: <token>
    • O token do Firebase App Check fornecido pelo app cliente que faz a solicitação. O back-end verifica automaticamente esse token e o decodifica, injetando o appId no context do gerenciador. Se não for possível verificar o token, a solicitação será rejeitada. (Disponível para SDK versão 3.14.0 ou posterior)

Se outros cabeçalhos forem incluídos, a solicitação será rejeitada, conforme descrito na documentação de resposta abaixo.

Observação: em clientes JavaScript, essas solicitações acionam uma pré-visualização do CORS OPTIONS pelos seguintes motivos:

  • O application/json não é permitido. Precisa ser text/plain ou application/x-www-form-urlencoded.
  • O cabeçalho Authorization não é um cabeçalho da solicitação listado no CORS.
  • Outros cabeçalhos também não são permitidos.

O acionador selecionável manipula automaticamente essas solicitações OPTIONS.

Corpo da solicitação

O corpo da solicitação HTTP deve ser um objeto JSON com qualquer um dos seguintes campos:

  • Obrigatório: data - o argumento passado para a função. Pode ser qualquer valor JSON válido. É automaticamente decodificado em tipos JavaScript nativos de acordo com o formato de serialização descrito abaixo.

Se houver outros campos presentes na solicitação, o back-end considerará a solicitação malformada e ela será rejeitada.

Formato de resposta: códigos de status

Há vários casos que podem resultar em códigos de status de HTTP e de string diferentes para erros na resposta.

  1. No caso de um erro HTTP antes de o acionador do client ser invocado, a resposta não é tratada como uma função do cliente. Por exemplo, se um cliente tentar invocar uma função não existente, ele receberá uma resposta 404 Not Found.

  2. Se o acionador do cliente for invocado, mas a solicitação estiver no formato errado, como não ser JSON, ter campos inválidos ou não incluir o campo data, a solicitação será rejeitada com 400 Bad Request, com um código de erro de INVALID_ARGUMENT.

  3. Se o token de autenticação fornecido na solicitação for inválido, a solicitação será rejeitada com 401 Unauthorized, com um código de erro UNAUTHENTICATED.

  4. Se o token de registro do FCM fornecido na solicitação for inválido, o comportamento será indefinido. O token não está marcado em todas as solicitações, exceto quando é usado para enviar uma notificação por push com o FCM.

  5. Se o acionador chamável for invocado, mas falhar com uma exceção não manipulada ou retornar uma promessa com falha, a solicitação será rejeitada com 500 Internal Server Error, com um código de erro de INTERNAL. Isso evita que erros de codificação sejam acidentalmente expostos a usuários finais.

  6. Se o acionador chamável for invocado e retornar uma condição de erro explícita usando a API fornecida para funções chamáveis, a solicitação falhará. O código de status HTTP retornado é baseado no mapeamento oficial do status de erro para o status HTTP, conforme definido no code.proto. O código de erro específico, a mensagem e os detalhes retornados são codificados no corpo da resposta, conforme detalhado abaixo. Isso significa que, se a função retornar um erro explícito com status OK, a resposta terá o status 200 OK, mas o campo error será definido na resposta.

  7. Se o acionador do cliente for bem-sucedido, o status da resposta será 200 OK.

Formato de resposta: cabeçalhos

A resposta tem os seguintes cabeçalhos:

  • Content-Type: application/json
  • Um ; charset=utf-8 opcional é permitido.

Corpo da resposta

A resposta de um ponto de extremidade do cliente é sempre um objeto JSON. No mínimo, ele contém result ou error, com qualquer campo opcional. Se a resposta não for um objeto JSON ou não contiver data ou error, o SDK do cliente deverá considerar que a solicitação falhou com o código de erro do Google INTERNAL (13).

  • error: se este campo estiver presente, a solicitação será considerada com falha, independentemente do código de status HTTP ou se data também estiver presente. O valor desse campo precisa ser um objeto JSON no formato Mapeamento HTTP do Google Cloud para erros, com campos para status, message e (opcionalmente) details. O campo code não deve ser incluído. Se o campo status não estiver definido ou for um valor inválido, o cliente deverá tratar o status como INTERNAL, de acordo com code.proto. Se details estiver presente, ele será incluído em qualquer informação do usuário anexada ao erro no SDK do cliente, se aplicável.
    Observação: o campo details é um valor fornecido pelo usuário. Não é necessariamente uma lista de valores codificados pelo tipo proto como no formato Status do Google.
  • result: o valor retornado pela função. Pode ser qualquer valor JSON válido. O SDK firebase-functions codifica automaticamente o valor retornado pelo usuário para esse formato JSON. Os SDKs do cliente decodificam automaticamente esses parâmetros em tipos nativos de acordo com o formato de serialização descrito abaixo.

Se outros campos estiverem presentes, eles devem ser ignorados.

Serialização

O formato de serialização para payloads arbitrários é o mesmo para a solicitação e a resposta.

Para manter a consistência da plataforma, eles são codificados em JSON como se fossem o valor de um campo Any em um buffer de protocolo proto3, usando o mapeamento JSON padrão. Valores de tipos simples, como null, int, double ou string, são codificados diretamente e não incluem o tipo explícito. Portanto, um float e um double são codificados da mesma maneira, e não é possível saber qual é recebido no outro lado da chamada. Para tipos que não são nativos para JSON, a codificação proto3 digitada para o valor é usada. Para mais informações, consulte a documentação "Qualquer codificação JSON".

Os seguintes tipos são permitidos:

  • null: null
  • int (assinado ou não, até 32 bits): por exemplo, 3 ou -30.
  • float: por exemplo, 3.14
  • double: por exemplo, 3.14
  • boolean: true ou false
  • string: por exemplo, "hello world"
  • map<string, any="">, por exemplo, {"x": 3}</string,>
  • list: por exemplo, [1, 2, 3]
  • long (assinado ou não, até 64 bits): mais detalhes abaixo

Os valores NaN e Infinity para float e double não são compatíveis.

Observe que long é um tipo especial que normalmente não é permitido em JSON, mas é coberto pela especificação proto3. Por exemplo, estes são codificados como:

long

{
    '@type': 'type.googleapis.com/google.protobuf.Int64Value',
    'value': '-123456789123456'
}

long não assinado

{
    '@type': 'type.googleapis.com/google.protobuf.UInt64Value',
    'value': '123456789123456'
}

Em geral, a chave @type deve ser considerada reservada e não usada para mapas passados.

Como o tipo não é especificado para tipos simples, alguns valores mudam de tipo após passarem pelo fio. Um float passado se torna um double. Um short se torna um int e assim por diante. No Android, List e JSONArray são compatíveis com valores de lista. Nesses casos, passar um JSONArray gerará um List.

Se um mapa com um campo @type desconhecido for cancelado, ele será deixado como um mapa. Assim, os desenvolvedores podem adicionar campos com novos tipos aos valores de retorno sem prejudicar clientes mais antigos.

Amostras de código

As amostras nesta seção ilustram como codificar o seguinte:

  • Um exemplo de callable.call no Swift
  • Uma resposta de êxito para a chamada
  • Uma resposta de falha para a chamada

Exemplo de Callable.call no Swift para codificação

callable.call([
    "aString": "some string",
    "anInt": 57,
    "aFloat": 1.23,
    "aLong": -123456789123456 as Int64
])

Cabeçalho da solicitação:

Method: POST
Content-Type: application/json; charset=utf-8
Authorization: Bearer some-auth-token
Firebase-Instance-ID-Token: some-iid-token

Corpo da solicitação:

{
    "data": {
        "aString": "some string",
        "anInt": 57,
        "aFloat": 1.23,
        "aLong": {
            "@type": "type.googleapis.com/google.protobuf.Int64Value",
            "value": "-123456789123456"
        }
    }
}

Resposta para codificação

return {
    "aString": "some string",
    "anInt": 57,
    "aFloat": 1.23
};

Cabeçalho de resposta bem-sucedida:

200 OK
Content-Type: application/json; charset=utf-8

Corpo de resposta bem-sucedida:

{
    "response": {
        "aString": "some string",
        "anInt": 57,
        "aFloat": 1.23
    }
}

Resposta com falha para codificação

throw new HttpsError("unauthenticated", "Request had invalid credentials.", {
  "some-key": "some-value"
});

Cabeçalho da resposta com falha:

401 UNAUTHENTICATED
Content-Type: application/json; charset=utf-8

Corpo de resposta com falha:

{
    "error": {
        "message": "Request had invalid credentials.",
        "status": "UNAUTHENTICATED",
        "details": {
            "some-key": "some-value"
        }
    }
}