Вызовы API

Эта страница — про кирпичики, из которых складывается вызов API во FlutterFlow. В конкретном запросе понадобится часть из них или все сразу — зависит от того, как устроен сервис.

Заголовки

Заголовки несут служебную информацию о запросе и ответе. Они делятся на две группы:

  • Заголовки запроса описывают, что именно запрашивается и кто запрашивает.
  • Заголовки ответа несут дополнительные сведения от сервера.

Передача заголовков

Чаще всего нужны два:

  • Authorization — авторизация запроса.
  • Content-Type — тип содержимого при отправке тела запроса в POST, PUT или PATCH.

Как их задать:

  1. Откройте вкладку Headers и нажмите + Add Header.
  2. Введите имя заголовка, двоеточие и значение — например, Content-Type: application/json.

инфо

Для POST-запроса Content-Type по умолчанию — application/json, так что для JSON его можно не указывать.

Токен авторизации

Закрытые API отдают данные только при наличии токена в заголовке.

Постоянный токен

Некоторые сервисы выдают токен, который не меняется, пока вы сами не выпустите новый.

  1. Откройте вкладку Headers и нажмите + Add Header.
  2. Введите Authorization, двоеточие и значение — например, Authorization: Bearer YOUR_TOKEN.

Динамический токен

Чаще токен приходит в ответе на запрос входа и меняется при каждом входе — значит, подставлять его нужно динамически.

внимание
Где хранить токен

После успешного входа сохраните токен в переменную App State с включённым Persisted:

api-token-variable.png

Дальше:

  1. Откройте вкладку Headers и нажмите + Add Header.
  2. Введите Authorization, двоеточие и имя переменной в квадратных скобках — например, Authorization: Bearer [auth_token].
  3. Откройте вкладку Variables и создайте переменную с тем же именем.

Теперь при вызове API значение подставляется из переменной App State.

Чтение заголовков ответа

Иногда нужное лежит не в теле ответа, а в его заголовках — например, токен после входа.

  1. Убедитесь, что действие вызова API добавлено и у него задано Action Output Variable Name.
  2. Там, где Value Source = From Variable, выберите Action Outputs > [имя переменной] — скажем, loginResponse.
  3. Задайте API Response Options = Get Response Header.
  4. Введите Header Name — он должен совпадать с именем заголовка в ответе.
  5. Нажмите Confirm.

Параметры запроса

Параметры уточняют, какие данные вернуть. Они дописываются в конец адреса после знака ? парами «ключ — значение».

Пример из NASA Open API:

https://api.nasa.gov/neo/rest/v1/feed?start_date=2015-09-07&end_date=2015-09-08&api_key=DEMO_KEY

Здесь start_date, end_date и api_key — параметры запроса.

Ещё пример: в адресе https://www.breakingbadapi.com/api/characters?limit=20&offset=0 параметр limit задаёт число записей на странице, а offset — сколько записей пропустить. Так устроена постраничная выдача со смещением.

Как их задать

Для запросов GET и DELETE:

  1. Откройте вкладку Query Parameters и нажмите + Add Query Parameter.
  2. Введите Name параметра.
  3. Задайте Value SourceSpecific Value или From Variable.
    1. Для динамического значения выберите From Variable и укажите готовую переменную (как создать переменную) либо нажмите + Create New Variable. Переменная создастся сразу с именем параметра, но её Type нужно задать во вкладке Variables.
    2. Для постоянного значения выберите Specific Value, задайте Type и введите Value.

Пример для адреса https://api.instantwebtools.net/v2/passenger?page=10&size=20:

Изредка параметры нужны и в запросах POST, PUT и PATCH. Тогда:

  1. Замените в адресе жёстко заданное значение именем в скобках: https://api.instantwebtools.net/v2/passenger?page=[page].
  2. Откройте вкладку Variables и создайте переменную с тем же именем.

Переменные

Переменные передают в вызов API данные из приложения:

  • токен авторизации из состояния приложения — в заголовок;
  • имя и пароль из полей ввода — в тело запроса;
  • выбранные даты — в параметры;
  • динамическую часть — в базовый адрес.

Создание переменных

Откройте вкладку Variables, введите Name, выберите Type и при необходимости задайте Default Value.

variables.png

Дальше значения передаются при вызове API со страницы — из виджета, переменной App State или другого источника.

Так выглядит динамический базовый адрес:

dynamic-base-url.png

Тело запроса

Запросы POST, PUT и PATCH передают данные в теле. Чаще всего — в формате JSON.

Форматы тела

JSON

  1. Если переменных ещё нет, создайте их — например, username и password для передачи со страницы входа.
  2. Откройте вкладку Body и выберите JSON.
  3. Вставьте своё тело запроса и замените значения переменными, перетащив их в нужные места.

Text

Текстовый формат нужен, когда тело — это, скажем, XML для SOAP-запроса.

  1. Если переменных ещё нет, создайте их.
  2. Откройте вкладку Body и выберите Text.
  3. Вставьте тело запроса и подставьте переменные перетаскиванием.

x-www-form-urlencoded

  1. Если переменных ещё нет, создайте их.
  2. Откройте вкладку Body и выберите x-www-form-urlencoded.
  3. Нажмите + Add Parameter и введите Name.
  4. Задайте Value SourceSpecific Value или From Variable.
    1. Для динамического значения выберите From Variable и укажите переменную либо создайте новую кнопкой + Create New Variable; её Type задаётся во вкладке Variables.
    2. Для постоянного значения выберите Specific Value, задайте Type и Value.

Multipart

Multipart передаёт в одном запросе несколько частей данных — так обычно загружают файлы.

  1. Откройте вкладку Body и выберите Multipart.
  2. Нажмите + Add Parameter и введите Name.
  3. Задайте Value Source = From Variable и создайте переменную кнопкой + Create New Variable.
  4. Во вкладке Variables задайте её Type = Uploaded File — тогда в запрос можно передать файл, полученный действием Upload/Save Media.

JSON и типы данных

Ответ API можно разбирать в собственный тип данных, а при отправке — собирать JSON из такого типа. Это те самые сериализация и десериализация.

инфо

Так надёжнее, чем ходить по JSON-путям вручную: опечатка в пути обнаружится в лучшем случае при тестировании, а несоответствие типов — сразу.

Тип данных под структуру ответа

Сначала создайте тип данных с той же структурой, что и ответ API.

custom-data-type-json-response.png

Тип данных, повторяющий структуру ответа

Дальше данные можно разбирать в тип или собирать из типа.

Из JSON в тип данных

Разберём на примере списка товаров из этого API:

img.png

Порядок действий:

  1. Создайте тип данных под структуру ответа.
  2. Откройте вызов API: Response & Test > Response Type и включите Parse as Data Type. Выберите нужный Data Type — в примере это «AllProducts».

img_1.png

  1. На виджете ListView после добавления запроса к API задайте:

    1. Generate Children from Variable с API Response Options = As Data Type.
    2. Available Options = Data Structure Field — нам нужно только поле со списком товаров, а не служебные total и skip.
    3. Select Field — поле со списком, в примере это «products».
    4. Дважды нажмите Confirm.

  1. Дальше данные привязываются к виджетам как обычно: Available Options = Data Structure Field и нужное поле в Select Field.

Из типа данных в JSON

Тело запроса можно собирать из объекта, а не описывать поле за полем в редакторе вызова.

Пример — добавление товара:

add-product.png

Порядок действий:

  1. Создайте тип данных под структуру тела запроса:

img_2.png

  1. В вызове API создайте переменную типа JSON и подставьте её в раздел Body.

  1. По нажатию кнопки Add значения из интерфейса записываются в переменную состояния страницы с этим типом данных. При вызове API передайте её и задайте Available Options = To JSON.

JSON-путь

JSONPath — язык запросов к JSON: по такому выражению из ответа достаётся ровно то, что нужно.

заметка

Ответ API почти всегда приходит в формате JSON.

Несколько выражений покрывают большинство задач, а конструктор подсказывает подходящие пути и показывает результат сразу.

Примеры выражений:

  • $.data.name
  • $.users[0].name
  • $.users[:].name

Знак $ означает корень, точка — обращение к ключу, число в скобках ([0]) — индекс элемента массива, а [:] выбирает все элементы списка.

Разберём на конкретном ответе:

{
  "page": 1,
  "per_page": 6,
  "total": 3,
  "total_pages": 2,
  "data": [
    {
      "id": 1,
      "email": "george.bluth@reqres.in",
      "first_name": "George",
      "last_name": "Bluth",
      "avatar": "https://reqres.in/img/faces/1-image.jpg"
    },
    {
      "id": 2,
      "email": "janet.weaver@reqres.in",
      "first_name": "Janet",
      "last_name": "Weaver",
      "avatar": "https://reqres.in/img/faces/2-image.jpg"
    },
    {
      "id": 3,
      "email": "emma.wong@reqres.in",
      "first_name": "Emma",
      "last_name": "Wong",
      "avatar": "https://reqres.in/img/faces/3-image.jpg"
    }
  ],
  "support": {
    "url": "https://reqres.in/#support-heading",
    "text": "To keep ReqRes free, contributions towards server costs are appreciated!"
  }
}
$.total

Вернёт:

3
$.data

Вернёт:

[
   {
      "id": 1,
      "email": "george.bluth@reqres.in",
      "first_name": "George",
      "last_name": "Bluth",
      "avatar": "https://reqres.in/img/faces/1-image.jpg"
   },
   {
      "id": 2,
      "email": "janet.weaver@reqres.in",
      "first_name": "Janet",
      "last_name": "Weaver",
      "avatar": "https://reqres.in/img/faces/2-image.jpg"
   },
   {
      "id": 3,
      "email": "emma.wong@reqres.in",
      "first_name": "Emma",
      "last_name": "Wong",
      "avatar": "https://reqres.in/img/faces/3-image.jpg"
   }
]
$.data[0]

Вернёт объект с индексом 0 — то есть первый:

{
   "id": 1,
   "email": "george.bluth@reqres.in",
   "first_name": "George",
   "last_name": "Bluth",
   "avatar": "https://reqres.in/img/faces/1-image.jpg"
}
$.data[0].email

Вернёт значение поля email у первого объекта:

"george.bluth@reqres.in"
$.data[:].email

Вернёт адреса почты всех объектов из data:

[
  "george.bluth@reqres.in",
  "janet.weaver@reqres.in",
  "emma.wong@reqres.in"
]
внимание
Важно

Ключи JSON начинаются с буквы, подчёркивания или знака доллара, но не с цифры. Если ключ всё же начинается с цифры — например, 0_image, — обращайтесь к нему через скобки: $.["0_image"].

инфо

Подробности о JSONPath и о том, как составлять выражения.

Сохранённые JSON-пути

Часто используемые пути удобно сохранить и дальше выбирать их из списка как Predefined Path.

Сначала создайте и протестируйте вызов. В разделе JSON Paths нажмите + Add JSON Path, введите выражение и дайте ему имя. Если выражение верное, под ним появится Response Preview; значок Preview открывает полный ответ. Для списка значений опция Is List включится сама.

В разделе Recommended конструктор предлагает пути, где, скорее всего, лежат нужные данные.

Использование пути

Обращаясь к значению из ответа, можно ввести путь вручную или взять сохранённый.

Выберите ответ вашего API, задайте API Response Options = JSON Body, а Available OptionsJSON Path или Predefined Path, и укажите имя пути.

Дополнительные настройки

Здесь вызов делают приватным и меняют настройки прокси.

Приватные вызовы

Приватный вызов нужен, когда в запросе есть токен или секрет, которому не место в коде приложения: такой вызов идёт через облачные функции Firebase.

private-cloud-func.png

Откройте вкладку Advanced Settings, включите Make Private, нажмите Save, а затем Deploy APIs.

Дополнительно можно потребовать, чтобы вызов выполнялся только авторизованным пользователем, — переключатель Require Authentication.

Приватные API разворачиваются как Cloud Functions в вашем проекте Firebase. При этом настраиваются:

  • Use Custom Name for Cloud Function — своё имя облачной функции; по умолчанию она называется ffPrivateApiCall.

  • Private API Cloud Function Instances — число экземпляров функции:

    • Min Instances — сколько экземпляров держать «тёплыми», чтобы избежать холодного старта. Значение больше нуля ускоряет отклик, но стоит денег.
    • Max Instances — предел масштабирования под нагрузкой.

    Чтобы не платить лишнего, Min Instances можно оставить равным 0. Цены — на странице тарифов Cloud Functions.

заметка

Потоковый ответ

Если API отдаёт данные непрерывно — например, через Server Sent Events, — включите эту настройку: приложение будет принимать поток по длительному HTTP-соединению и показывать обновления по мере поступления.

Так работает, скажем, приложение с онлайн-табло спортивных результатов.

инфо

Поддерживает ли API потоковую передачу, обычно видно в его документации — по словам «event stream» или «processing chunks».

заметка
Подробнее

Как устроены потоковые API.

Настройки прокси

При тестировании вызовов в конструкторе, а также в режимах Run и Test запросы идут через прокси — иначе мешает политика CORS. При желании можно указать свой прокси.

  1. Откройте вкладку Advanced Settings.
  2. Выключите Use Proxy for Test и/или Use Proxy for Run/Test Mode.
  3. Включите Use Custom Proxy URL.
  4. Введите Proxy Prefix URL — например, https://your-proxy-server.com.

proxy-settings.png

Кеширование результатов

Для отдельного вызова можно включить кеширование: повторные обращения с теми же аргументами будут брать данные из кеша. Подробнее — в разделе о кешировании запросов.

Чтение ответа как UTF-8

Обычно сервер сам сообщает кодировку ответа, но не всегда. Эта настройка заставляет читать ответ как UTF-8 в любом случае.

Перехватчики

Перехватчик (interceptor) вклинивается между приложением и сервером: он видит запрос до отправки и ответ до того, как тот дойдёт до приложения. Через него добавляют токены, ведут журнал и обрабатывают ошибки.

Запрос сначала попадает в перехватчик: тот может изменить его — дописать заголовки, поправить адрес — или вовсе отменить. Ответ проходит обратный путь.

Как добавить перехватчик:

  1. Откройте вкладку Advanced Settings.

  2. Нажмите + Add Interceptors и выберите + Create New Interceptor — откроется редактор кастомного действия.

  3. Введите Action Name.

  4. В заготовке кода опишите обработку запроса в функции onRequest, а обработку ответа — в onResponse.

  5. Сохраните действие и проверьте, нет ли ошибок.

  6. Новый перехватчик появится в списке API interceptors.

совет
Заодно
  • К одному вызову можно добавить несколько перехватчиков.
  • Если перехватчик нужен нескольким вызовам, соберите их в группу и добавьте его в Advanced Group Settings; для отдельного вызова внутри группы его можно переопределить.

:::tip[Видео] Если удобнее посмотреть:

:::

Частые вопросы

Почему сохранённый JSON-путь не появляется в списке?

Чаще всего путь добавили, но забыли сохранить сам вызов API. Нажмите Save после изменений — тогда FlutterFlow увидит сохранённые пути.

Откуда ошибка «Current variable is not valid»?

Виджет получает не тот тип данных, которого ждёт: например, в текстовый виджет передали список цветов. Приведите значение к подходящему типу — скажем, к строке.

перевод официальной документации FlutterFlow

обновлено

ESC