Спецификация протокола для 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 из Firebase client SDK. Это должна быть строка. Это доступно в 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 не установлено или имеет недопустимое значение, клиент должен рассматривать status как INTERNAL в соответствии с code.proto . Если details присутствуют, они включаются в любую пользовательскую информацию, прикрепленную к ошибке в клиентском SDK, если применимо.
    Примечание: Поле details здесь — это значение, введенное пользователем. Это не обязательно список значений, привязанных к типу прототипа, как в формате Google Status .
  • result - Значение, возвращаемое функцией. Это может быть любое допустимое значение JSON. Firebase-functions SDK автоматически кодирует возвращаемое пользователем значение в этот формат 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]
  • long (со знаком или без знака, до 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"
        }
    }
}