SOAP API

SOAP (Simple Object Access Protocol) — способ обмена данными между системами: сообщения в формате XML передаются поверх HTTP, SMTP и других протоколов.

В отличие от REST, где формат ответа гибкий и обычно это JSON, SOAP опирается на формальный контракт WSDL. Отсюда и характер: строже, зато предсказуемее — что ценят там, где важны целостность транзакций и гарантированная доставка сообщений.

Такие API часто встречаются в финансах и телекоме — там, где нужны серьёзная защита и подробная обработка ошибок.

Чем SOAP отличается от REST

Протокол и формат. SOAP завязан на протокол и XML, REST гибче: обычные методы HTTP и любой формат данных — JSON, XML и прочие.

Соединение. И там и там запросы независимы, но REST при этом не хранит состояние, поэтому масштабируется проще.

Когда что. SOAP — там, где нужны формальный контракт и высокая защищённость; REST — для лёгких и хорошо масштабируемых сервисов.

Ответ SOAP

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  <soap:Body>
    <GetMatchScoreResponse xmlns="http://example.com/scores">
      <MatchScore>
        <Team1>Red Dragons</Team1>
        <Team2>Silver Sharks</Team2>
        <Score>2-1</Score>
      </MatchScore>
    </GetMatchScoreResponse>
  </soap:Body>
</soap:Envelope>

Ответ REST

{
  "event": "match_score",
  "data": {
    "team1": "Red Dragons",
    "team2": "Silver Sharks",
    "score": "2-1"
  }
}

Собираем приложение

Разберём SOAP на примере: список стран, а по нажатию на страну — экран с её флагом.

Вот что получится:

инфо
Что разберём
  • как описать вызов SOAP API;
  • как передать динамические данные в тело запроса;
  • как разобрать ответ в формате XML;
  • как перейти на другую страницу и передать туда данные.

Понадобятся две страницы:

  1. HomePage — список стран.
  2. CountryDetails — флаг выбранной страны.

Переходы между ними:

Схема переходов

1. Интерфейс

1.1 Главная страница

Список стран выводится виджетами ListView и ListTile.

HomePage

1.2 Страница страны

Флаг показывается виджетом Image.

CountryDetails

2. Вызовы API

Возьмём два вызова из публичных SOAP API Postman:

  1. getCountries
  2. getCountryFlag

Прежде чем строить на API интерфейс, вызовы нужно создать и проверить.

2.1 getCountries

Возвращает список стран с их кодами. Добавляется как обычный вызов.

инфо

Два обязательных момента: заголовок «Content-Type: text/xml; charset=utf-8» и тип тела запроса Text.

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

2.2 getCountryFlag

Возвращает флаг страны по её коду. Код передаётся в тело запроса переменной.

Тело запроса

Тело запроса

Заголовок

3. Кастомные действия

Оба вызова возвращают XML — его нужно разобрать. Для этого подойдёт кастомное действие с пакетом xml: оно достанет из ответа то, что можно показать в виджетах.

Понадобятся два действия — по одному на каждый вызов.

3.1 parseListofCountries

Разбирает ответ getCountries и возвращает список стран — List из String.

Код с пояснениями в комментариях:

// Automatic FlutterFlow imports
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/actions/index.dart'; // Imports other custom actions
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom action code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!

import 'package:xml/xml.dart';

Future<List<String>> parseListofCountries(String xmlResponse) async {
  final document = XmlDocument.parse(xmlResponse);
  final countryList = <String>[]; // Создаём пустой список под страны

  // Находим все элементы с тегом 'm:tCountryCodeAndName'
  final countryElements = document.findAllElements('m:tCountryCodeAndName');
  // Проходим по каждому найденному элементу
  for (final countryElement in countryElements) {
    // Достаём код страны
    final countryCode = countryElement.findElements('m:sISOCode').single.text;
    // Достаём название страны
    final countryName = countryElement.findElements('m:sName').single.text;
    // Кладём код и название в список одной строкой
    countryList.add('$countryCode - $countryName');
  }

  print(countryList);
  return countryList;
}

Так это выглядит после добавления:

Кастомное действие для разбора списка стран

3.2 parseCountryDetails

Разбирает ответ getCountryFlag: цепочкой обращений доходит до нужного элемента и забирает ссылку на флаг.

// Automatic FlutterFlow imports
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/actions/index.dart'; // Imports other custom actions
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom action code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!

import 'package:xml/xml.dart';

Future<String> parseCountryDetails(String xmlResponse) async {
  final document = XmlDocument.parse(xmlResponse);

  return document
      .getElement('soap:Envelope')! // Элемент soap:Envelope
      .getElement('soap:Body')! // Элемент soap:Body
      .getElement('m:CountryFlagResponse')! // Элемент m:CountryFlagResponse
      .getElement('m:CountryFlagResult')! // Элемент m:CountryFlagResult
      .text // Текст элемента
      .trim(); // Убираем лишние пробелы
}

Так это выглядит после добавления:

Кастомное действие для разбора ответа с флагом

4. Список стран

  1. Откройте HomePage.

  2. Создайте переменную состояния страницы — например, countries: в неё ляжет список для ListView.

    Переменная состояния страницы

  3. Выделите страницу и добавьте цепочку действий:

    1. вызов getCountries;
    2. при успехе — кастомное действие parseListOfCountries. Результат предыдущего вызова передаётся аргументом, а API Response Options должно быть равно Raw Body Text; не забудьте задать Action Output Variable Name;
    3. обновление состояния страницы: переменной countries присваивается результат кастомного действия. Update TypeRebuild Current Page.

  4. У ListView сгенерируйте дочерние элементы из этой переменной.

  5. В переменной название и код лежат одной строкой — «Australia - AT». Чтобы показать их по отдельности в ListTile, пригодится встроенное выражение: название — var1.split("-")[1].trim(), код — то же выражение с индексом [0].

5. Переход на страницу страны

По нажатию на страну открывается CountryDetails, куда передаётся код страны — по нему дальше запрашивается флаг.

  1. Выделите ListTile и добавьте переход на CountryDetails.
  2. Нажмите Define — откроется страница CountryDetails, где нужно описать параметр под код страны.
  3. Вернитесь к действию перехода и передайте код тем же выражением: var1.split("-")[0].trim().

Параметр страницы

Параметр на странице CountryDetails

Передача кода страны

Передача кода страны при переходе

6. Флаг страны

Код страны приходит на страницу параметром — по нему запрашивается флаг.

  1. Откройте CountryPage.

  2. Создайте переменную состояния страницы с типом ImagePath — например, flagURL.

    Переменная под ссылку на флаг

  3. Выделите страницу и добавьте цепочку действий:

    1. вызов getCountryFlag;
    2. при успехе — кастомное действие parseCountryDetails. Результат вызова передаётся аргументом, API Response OptionsRaw Body Text, плюс Action Output Variable Name;
    3. обновление состояния страницы: в flagURL попадает результат кастомного действия. Update TypeRebuild Current Page.

  4. Осталось привязать переменную к виджету Image.

    Вывод изображения из переменной состояния

Готовый пример

Клонируемая версия этого приложения — здесь.

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

обновлено

ESC