В книге Арно Лоре “Проектирование веб-API” (5.3.1 Построение простой цепочки целей) есть пример API для мобильного банкинга, где клиент пытается перевести деньги бенефециару, справляясь с трудностями бизнес-логики (сумма превышает безопасный лимит; сумма превышает совокупный дневной лимит перевода; исходный счет нельзя использовать в качестве источника перевода; данный вариант назначения нельзя использовать с этим источником). На картинках рассаматривается такая эволюция целей API:

Но разве нельзя сделать это короче и более плавно, предотвращая ошибки?

С помощью этой новой цели можно предотвратить три из четырех ошибок!

Новая агрегированная цель возвращает только возможные варианты назначения для данного источника, причем источник извлекается с помощью цели «Перечислить источники». Эта новая цель упростит поток целей, и тут есть бонус! Это также предотвращает появление ошибки «Данный вариант назначения нельзя использовать с этим источником». Теперь у потребителей меньше целей для использования, и у них есть доступ ко всему, что нужно, чтобы избежать сообщений об ошибках от цели «Перевод денег».
В этом сценарии клиент последовательно вполняет три шага:
- Получает список источников
- Получает список назначений для выбранного источника
- Переводит выбранную сумму из выбранного источника в выбранное назначение
Псевдокод:
sources = API.getSources() destinations = API.getDestinations(source[i]) API.makeTransfer(sources[i], destinations[j], amount)
Не смотря на то, что на рисунках приуствтует слово “цель” эволюция API движется вопросом “как?”, а не “зачем?”.
Получается API, который выглядит так, будто цель клиента при переводе денег – это избавиться от денег. Обычно переводы имеют внешнюю цель – финансовое обеспечение каких-то выгод (оплата заказов, внесение депозита). То есть они используются не для того, чтобы денег где-то не стало, а чтобы они где-то появились. Из этого следует, что изначально клиент знает назначение и сумму перевода, а источник определяется исходя из возможностей. Почему бы не использовать ценарий, в котором клиент:
- Получает список назначений
- Получает список источников для выбранного назначения
- Переводит выбранную сумму из выбранного источника в выбранное назначение
Псевдокод:
destinations = API.getDestinations() sources = API.getSources(destinations[j]) API.makeTransfer(sources[i], destinations[j], amount)
Отчасти это решается “последней оптимизацией”, которая представлена ниже.

Поскольку количество возможных комбинаций «источник вариант назначения» относительно ограничено, мы можем предоставить все возможные ассоциации «источник вариант назначения» с помощью одной цели «Перечислить варианты назначения и источники», которая объединяет цели «Перечислить источники» и «Перечислить варианты назначения для источника». Это не обязательно, но возможно.
Этот вариант предлагает получить все возможные пары (источник, назначение) и после этого перевести деньги. И он приемлем, пока источников и назначений мало. Например, при наличии трёх источников и десяти назначений количество пар может достигнуть 30. Передавать клиенту много данных без необходимости не особо хорошая идея, кроме того, это вынудит клиента решать проблемы их отображения и фильтрации (что критиковалось в 5.3.2).