Разработка API для международных рынков

Разработка API для международных рынков
Разработка API для международных рынков - davidclode @ Unsplash

Я работаю над REST API для компании, которая до недавнего времени была ориентирована на австралийский рынок. Результатом этого является то, что у API есть ресурсы и области, которые моделируют австралийский рынок, особенно в отношении налогообложения, пенсионного возраста и т. д. Сейчас мы стремимся выйти на зарубежные рынки, начиная с Новой Зеландии.

Очевидно, что между ними будет некоторая степень совпадения, но как люди справляются с различиями в терминологиях и концепциях и как лучше переключаться между ними? Например, API может вернуть список сотрудников, нанятых компанией; некоторые из этих сотрудников базируются в Австралии, а некоторые в Новой Зеландии. Налоговая информация сотрудника будет иметь уникальный идентификатор, предоставленный соответствующим налоговым органом (ATO в Австралии, IRD в Новой Зеландии), базовую заработную плату, контрактное количество часов в неделю и налоговый код по умолчанию (Налоговый кодекс в Австралии и налоговая шкала в Новой Зеландии).

Как бы вы представили эту информацию в REST API? Я хочу максимально избегать подхода EAV; значит ли это, что мне нужно использовать какую-то модель, основанную на наследовании?

например

public abstract class TaxDetails {
  public string EmployeeReference { get;set; }
  public decimal BasicSalary { get;set; }
  public decimal HoursPerWeek { get;set; }
}

public class AustraliaTaxDetails : TaxDetails {
  public string TaxCode { get;set; }
}

public class NewZealandTaxDetails : TaxDetails {
  public string TaxScale { get;set; }
}

или мне оставить «более простую» модель и просто не устанавливать значения, которые не применяются в одном регионе, и позволить сериализатору привести модель в порядок? например

public class TaxDetails {
  public string EmployeeReference { get;set; }
  public decimal BasicSalary { get;set; }
  public decimal HoursPerWeek { get;set; }
  public string? TaxScale { get;set; }
  public string? TaxCode { get;set; }
}

Третий вариант будет похож на второй, но попытайтесь найти нейтральный термин для полей, которые семантически одинаковы, но отличаются только именами (например, TaxScale против TaxCode). Это похоже на худшее из решений (особенно потому, что называть вещи сложно), и вам все равно приходится иметь дело со случаями, когда между двумя разными регионами нет прямых эквивалентов; и масштабироваться будет еще хуже, когда вы начнете рассматривать более двух регионов...

Так. Как вы, добрые люди, справитесь с таким сценарием?

Судя по вашему повествованию, у вас действительно есть общая модель с несколькими специфическими для страны специализациями. Эта ситуация в принципе соответствует наследованию.

Но REST API — это то, что вы должны проектировать без учета наследования, потому что для клиентских приложений вопрос заключается в том, как использовать опубликованный API. Он не должен беспокоиться о внутренней модели серверной части.

Решения очень похожи на то, что существует в традиционном сопоставлении ORM, за исключением того, что оно предназначено для сопоставления API:

  • вы можете предоставить специализированные конечные точки для адаптированного API для конкретной страны. Это самый чистый подход и самый простой для использования (в ORM это будет соответствовать наследованию конкретных таблиц). Однако это может быть очень громоздко, если у вас много небольших вариаций.
  • вы можете поместить все поля в свой API и использовать только релевантные (в ORM это соответствует наследованию одной таблицы) Но, пожалуйста, четко документируйте (использовав такие API, я могу сказать, что часто приходится гадать, какое поле в каких случаях можно использовать). Это не в духе принципа разделения интерфейсов, но очень практично, особенно если разница только в нескольких полях.
  • теоретически вы также можете предложить базовый интерфейс и позволить клиенту составлять элементы, вызывая некоторую дополнительную конечную точку, чтобы получить специфику (это соответствует наследованию таблицы классов в ORM). Но хотя он хорошо реализует принцип композиции по наследованию, его сложнее использовать. Сохраняйте этот подход для более сложных моделей, где ни одна из первых не дает удовлетворительного ответа. (например, если бы речь шла не просто о налоговом кодексе или шкале налогов, а о полной налоговой схеме с множеством дополнительных деталей и правил).

Так что, если речь идет только о налоговом коде и налоговой шкале, агрегированный API выглядит нормально.


LetsCodeIt, 31 декабря 2022 г., 17:21