Спецификация протокола для 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 App Check предоставляется клиентским приложением, отправляющим запрос. Бэкенд автоматически проверяет этот токен и декодирует его, внедряя 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 Protocol Buffer, используя стандартное сопоставление JSON . Значения простых типов, таких как null , int , double или string кодируются напрямую и не содержат явного указания типа. Таким образом, числа float и double кодируются одинаково, и вы можете не знать, какой из них будет получен на другом конце вызова. Для типов, не являющихся собственными для JSON, используется типизированное кодирование Proto3 для значения. Для получения дополнительной информации см. документацию по кодированию Any JSON .

Допускаются следующие типы:

  • нулевой - null
  • int (знаковое или беззнаковое, до 32 бит) - например 3 или -30 .
  • плавающий - например, 3.14
  • double - например, 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 поддерживаются как 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"
        }
    }
}