Спецификация протокола для https.onCall

Триггер https.onCall для Cloud Functions — это HTTPS-триггер с определённым форматом запроса и ответа. В этом разделе представлена спецификация форматов HTTPS-запросов и ответов, используемых клиентскими SDK для реализации API. Эта информация может быть полезна, если ваши требования невозможно удовлетворить с помощью платформ Android, Apple или веб-SDK.

Формат запроса: заголовки

HTTP-запрос к вызываемой конечной точке триггера должен быть POST со следующими заголовками:

  • Требуется: Content-Type: application/json
    • Допускается необязательный параметр ; charset=utf-8 .
  • Необязательно: Authorization: Bearer <token>
    • Токен идентификатора пользователя Firebase Authentication для вошедшего в систему пользователя, выполняющего запрос. Бэкенд автоматически проверяет этот токен и делает его доступным в context обработчика. Если токен недействителен, запрос отклоняется.
  • Необязательно: Firebase-Instance-ID-Token: <iid>
    • Регистрационный токен FCM из клиентского SDK Firebase. Должен быть строкой. Доступен в context обработчика. Используется для таргетинга push-уведомлений.
  • Необязательно: X-Firebase-AppCheck: <token>
    • Токен проверки приложения Firebase, предоставленный клиентским приложением, выполняющим запрос. Бэкенд автоматически проверяет этот токен и декодирует его, внедряя appId в context обработчика. Если токен не может быть проверен, запрос отклоняется. (Доступно для SDK >=3.14.0)

Если включены какие-либо другие заголовки, запрос отклоняется, как описано в документации по ответу ниже.

Примечание: в клиентах JavaScript эти запросы запускают предварительную проверку CORS OPTIONS , потому что:

Вызываемый триггер автоматически обрабатывает эти запросы OPTIONS .

Текст запроса

Тело HTTP-запроса должно представлять собой JSON-объект с любым из следующих полей:

  • Обязательно: data — аргумент, передаваемый функции. Это может быть любое допустимое значение JSON. Оно автоматически декодируется в собственные типы JavaScript в соответствии с форматом сериализации, описанным ниже.

Если в запросе присутствуют какие-либо другие поля, бэкэнд считает запрос некорректным и отклоняет его.

Формат ответа: коды статуса

Существует несколько случаев, которые могут привести к разным кодам состояния HTTP и строковым кодам состояния для ошибок в ответе.

  1. В случае возникновения HTTP-ошибки до вызова client триггера ответ не обрабатывается как клиентская функция. Например, если клиент пытается вызвать несуществующую функцию, он получает ответ 404 Not Found .

  2. Если триггер клиента вызван, но запрос имеет неправильный формат, например, не является JSON, имеет недопустимые поля или отсутствует поле data , запрос отклоняется с кодом 400 Bad Request и кодом ошибки INVALID_ARGUMENT .

  3. Если предоставленный в запросе токен авторизации недействителен, запрос отклоняется с кодом 401 Unauthorized и кодом ошибки UNAUTHENTICATED .

  4. Если токен регистрации FCM, предоставленный в запросе, недействителен, поведение не определено. Токен не проверяется при каждом запросе, за исключением случаев, когда он используется для отправки push-уведомления через FCM.

  5. Если вызываемый триггер вызывается, но завершается сбоем из-за необработанного исключения или возвращает невыполненное обещание, запрос отклоняется с 500 Internal Server Error с кодом INTERNAL . Это предотвращает случайное появление ошибок кодирования у конечных пользователей.

  6. Если вызываемая функция вызывается и возвращает явное состояние ошибки с использованием API, предоставляемого для вызываемых функций, запрос завершается ошибкой. Возвращаемый код статуса HTTP основан на официальном сопоставлении статуса ошибки со статусом HTTP, как определено в code.proto . Конкретный код ошибки, сообщение и возвращаемые сведения кодируются в теле ответа, как подробно описано ниже. Это означает, что если функция возвращает явную ошибку со статусом OK , то ответ имеет статус 200 OK , но поле error в ответе установлено.

  7. Если клиентский триггер успешен, статус ответа — 200 OK .

Формат ответа: заголовки

Ответ имеет следующие заголовки:

  • Content-Type: application/json
  • Допускается необязательный параметр ; charset=utf-8 .

Тело ответа

Ответ от клиентской конечной точки всегда представляет собой JSON-объект. Он содержит как минимум либо result , либо error , а также любые необязательные поля. Если ответ не является JSON-объектом или не содержит data или error , клиентский SDK должен считать запрос неудачным с кодом ошибки Google INTERNAL (13) .

  • error — если это поле присутствует, запрос считается невыполненным, независимо от кода статуса HTTP или наличия data . Значение этого поля должно быть JSON-объектом в стандартном формате Google Cloud HTTP Mapping для ошибок с полями status , message и (необязательно) details . Поле code не должно быть включено. Если поле status не задано или имеет недопустимое значение, клиент должен рассматривать статус как INTERNAL , в соответствии с code.proto . Если details присутствуют, они включаются в любую пользовательскую информацию, прикрепленную к ошибке в клиентском SDK, если применимо.
    Примечание: Поле details здесь представляет собой значение, вводимое пользователем. Оно не обязательно представляет собой список значений, упорядоченных по типу прототипа, как в формате Google Status .
  • result — значение, возвращаемое функцией. Это может быть любое допустимое значение JSON. SDK Firebase-functions автоматически кодирует возвращаемое пользователем значение в этот формат JSON. Клиентские SDK автоматически декодируют эти параметры в собственные типы в соответствии с форматом сериализации, описанным ниже.

Если присутствуют другие поля, их следует игнорировать.

Сериализация

Формат сериализации произвольных данных одинаков как для запроса, так и для ответа.

Для обеспечения согласованности платформы эти значения кодируются в JSON так, как если бы они были значением поля Any в буфере протокола Proto3, с использованием стандартного сопоставления JSON . Значения простых типов, таких как null , int , double или string кодируются напрямую, без явного указания типа. Таким образом, float и double кодируются одинаково, и вы можете не знать, какой тип получен на другом конце вызова. Для типов, не являющихся собственными для JSON, используется типизированная кодировка Proto3 для значения. Подробнее см. в документации по кодировке Any JSON .

Разрешены следующие типы:

  • ноль - null
  • int (со знаком или без знака, до 32 бит) - например, 3 или -30 .
  • плавающее число - например, 3.14
  • двойной - например, 3.14
  • логическое значение - true или false
  • строка - например, "hello world"
  • карта - например {"x": 3}
  • список - например [1, 2, 3]
  • длинное (со знаком или без знака, до 64 бит) - [подробности см. ниже]

Значения NaN и Infinity для float и double не поддерживаются.

Обратите внимание, что long — это особый тип, который обычно не допускается в JSON, но охвачен спецификацией proto3. Например, они кодируются следующим образом:

длинный

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

беззнаковый длинный

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

В общем случае ключ @type следует считать зарезервированным и не использовать для переданных карт.

Поскольку для простых типов тип не указан, некоторые значения изменят тип после передачи. Переданное float становится значением double . short становится значением int , и так далее. В Android для списочных значений поддерживаются как List , так и JSONArray . В этих случаях передача JSONArray вернет значение List .

Если карта с неизвестным полем @type десериализуется, она остаётся в виде карты. Это позволяет разработчикам добавлять поля с новыми типами в возвращаемые значения, не нарушая работу старых клиентов.

Примеры кода

Примеры в этом разделе иллюстрируют, как кодировать следующее:

  • Пример callable.call на Swift
  • Успешный ответ на вызов
  • Ответ на отказ в вызове

Пример Callable.call на Swift для кодирования

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

Заголовок запроса:

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

Текст запроса:

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

Ответ на кодирование

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

Заголовок успешного ответа:

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

Успешный ответ:

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

Ошибка ответа на кодирование

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

Заголовок ответа при неудачном завершении:

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

Тело ответа не удалось:

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