Пост

API с полиморфизмом

В этом посте делюсь кратким пересказом главы из книги “API Design Patterns” Дж. Дж. Гивакса, где рассматривается использование полиморфизма в проектировании API.

Зачем это нужно? Полиморфизм в ООП позволяет работать с объектами разных типов через общий интерфейс. Например, для фигур Triangle и Square можно реализовать метод countSides(), который будет работать с общим типом Shape. Перенос этой концепции в API так же позволяет вместо отдельных эндпоинтов для каждого типа ресурса (например, Triangle и Square) создать один метод. Но у этого подхода есть свои сложности и нюансы, особенно в контексте JSON и HTTP. Цель данного паттерна — предложить безопасный способ внедрения полезных аспектов полиморфизма в ресурсно-ориентированные API.

Полиморфные ресурсы идеально подходят, когда объекты имеют схожие черты, как, например, разные типы сообщений в чате (TextMessage, PhotoMessage). В таких случаях можно создать обобщённый ресурс Message, который упростит получение данных через стандартные методы API. Однако если ресурсы имеют разные паттерны взаимодействия (например, ChatRoom и Broadcast), то лучше их разделить, чтобы избежать путаницы и сохранить удобство работы с API.

Итак, что важно для реализации? Полиморфные ресурсы обычно имеют поле type, который позволит определить тип ресурса. Поле должно быть строкой. В качестве типа этого поля может возникнуть соблазн использовать перечисления, но они могут вызывать множество проблем (об этом в отдельном посте расскажу). Изменение названия типа после создания не рекомендуется, чтобы избежать ошибок и нарушений целостности данных.

Для хранения данных полиморфных ресурсов можно использовать надмножество полей, охватывающее все возможные типы. Также можно абстрагировать содержимое в одно поле content, у которого будет разный тип в зависимости от типа ресурса:

1
2
3
4
5
6
7
interface Message {
    id: string;
    sender: string;
    type: 'text' | 'photo' | 'audio' | 'video';
    content: string | Media;
    ...
}

Не забываем про валидацию! Полиморфные ресурсы требуют разных подходов к валидации данных. Например, для ресурса Message текстовые сообщения будут содержать текст, а в случае медиа, например с типом photo, содержимым уже должен быть URI. Важно тщательно валидировать данные, чтобы избежать ошибок, особенно если поля противоречат друг другу (например, если передаются параметры, несовместимые с типом ресурса).

Полиморфные методы, такие как POST /{id=shapes}:countSides, могут работать одинаково для разных типов фигур, тем самым упрощая взаимодействие с ресурсами. Однако важно быть осторожным с их применением, чтобы не нарушить принципы разделения ответственности.

Почему не стоит использовать полиморфные методы? Стоит быть особенно осторожными с обобщенными методами, типа DeleteResource(). Такие методы напоминают использование типа any в аргументах функций, где можно передать значение любого типа - function deleteResource(resource: any): void. Хотя это упрощает работу с API, оно может привести к проблемам, так как разные типы ресурсов могут требовать разной обработки. Например, метод DeleteResource() может не учесть различия между жестким и мягким удалением для разных типов. В таких случаях лучше использовать отдельные методы для каждого типа ресурса.

Подытожим. Полиморфизм в API - это крутая штука, которая помогает уменьшить дублирование функциональности. Важно поддерживать стабильность строкового поля type и правильно валидировать данные. Стоит помнить, что полиморфные методы не всегда оправданы, так как они могут усложнить и ограничить API.

Авторский пост защищен лицензией CC BY 4.0 .

© Ainur. Некоторые права защищены.

Использует тему Chirpy для Jekyll