Payload и опыт взаимодействия с ним

Привет! Меня зовут Сергей, я ведущий разработчик в Lad. В этой статье речь пойдет об опыте работы с Payload.

В нашей компании мы использовали Payload для создания быстрых прототипов и MVP-проектов. Payload мы выбрали как весьма гибкий и интересный инструмент, предоставляющий большой функционал из коробки, админ-панель и базовую работу с пользователями.

В основном статья будет касаться взаимодействия со стороны backend-части.

Плюсы и преимущества Payload

  1. Упрощает разработку проекта, а это быстрая и простая начальная установка и готовая структура проекта (что в целом может быть и минусом).

  1. Поддержка мультиязычности из коробки.

  1. Предоставляет авторизацию из коробки.

  1. Аутентификация происходит по классической связке «email — password».

Для авторизации используется Bearer-токен.

ff74d55aad9d6870a72606c6b0167e82.png

Сразу весь необходимый набор ручек работы с пользователем:

96fa5caa9d2d3b7dae60ce4051516a35.png

Также это может быть расширено посредством PassportJs, но на практике у нас не было необходимости его использовать.

  1. Access control на CRUD операции.

  2. Удобен для быстрого прототипирования. Если хочется за 30 минут запустить проект, описать несколько сущностей — решение крайне удобно.

  3. Предоставляет базовый CRUD.

После описания сущности для нее создается набор рутов, готовый для работы:

24cf66e9245fe12c44fd0f53f1ba2404.png

  1. Query-запросы (GraphQL). 

    Со стороны frontend появляется возможность выполнять простые запросы, включая сортировки и фильтрацию (equals, less_then, in и т. д.).

  2. Стандартизация запросов. Ошибки, пагинация, ответы и прочее — все находится в едином стиле.

  3. Поддержка Mongodb и Postgres и простая быстрая базовая работа с ними (в нашем случае мы использовали только mongo).

  4. Быстрое описание коллекции и генерация интерфейсов на ее основе:

export const Clients: CollectionConfig = {
 slug: 'clients',
 auth: {
   depth: 1,
   tokenExpiration: 28800,
   maxLoginAttempts: 5,
   lockTime: 30 * 1000,
 },
 labels: {
   plural: 'Клиенты',
   singular: 'Клиент',
 },
 admin: {
   useAsTitle: 'name',
 },
 fields: [
   {
     name: 'name',
     type: 'text',
     label: 'Имя',
   },
   {
     name: 'favoriteNumber',
     type: 'number',
     label: 'Любимое число',
   },
   {
     type: 'date',
     label: 'Дата рождения',
     name: 'dateOfBirth',
   },
 ],
};

Интерфейс на выходе:

/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "clients".
*/
export interface Client {
 id: string;
 name?: string | null;
 favoriteNumber?: number | null;
 dateOfBirth?: string | null;
}
  1. Хорошая и удобная админка из коробки:

5571d9ca234dc1447d22b2e6bca31384.png

  1. Система предоставляет множество хуков на сущности и на поля. Часто это может быть очень удобно.

hooks: {
afterRead: [afterReadUser], 
afterDelete: [afterDeleteUser],
}

С какими минусами Payload мы столкнулись

Из некоторых плюсов вытекают минусы.

  1. Проблема хуков. Система предоставляет несколько уровней хуков. Одни хуки на уровне полей, вторые — на уровне коллекций. В нашей воле описать хуки на создание, изменение и удаление. 

    Звучит весьма неплохо. Но на определенном этапе работы с проектом выходит так, что не все вещи удобно и возможно делать через хуки + их становится слишком много.

    Это начинает выглядеть как усложнение. Встает проблема с тем, что приходится помнить и следить за всеми описанными хуками. Похоже на проблему с колбэками — это некая непредсказуемость кода: в какой момент и что выполнится? Все слишком нелинейно. Слишком запутанно.

  2. Типы и поля. Больше похоже на то, что они заточены на админ-панель, а не на бэкенд-часть. Яркий пример — это тип boolean, который здесь называется checkbox:

e4e73d34b20983d554631ed1d42068e6.png

  1. Проблема с mongoose. На момент разработки Payload использовал старый драйвер mongoDb. Обновить его просто так нельзя. Возникают различные проблемы, особенно проблемы, связанные с типами.

  2. Базы данных. Слишком высокий уровень абстракции. БД — mongoose — обертка на Payload. Появляется некая непредсказуемость того, что может произойти.

  3. Концепция Payload заставляет писать БД в стиле ближе к реляционному с огромным количеством таблиц и связей между ними.

  4. Если нужны более сложные запросы, то они будут работать в обход хуков. Приходится очень внимательно следить за этим. Часто это сильно усложняет и замедляет процесс разработки.

  5. Мелкие проблемы, которые возникают в процессе работы:

    • невозможно типизировать JSON-тип;

    • нельзя указать минимальное значение массива 0;

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

  1. Если нужно сделать более сложную валидацию и проверку данных, то приходится делать кастомный контроллер либо оборачивать дополнительными хуками. Но тогда как будто ломается концепция чего-то «быстрого из коробки».

  2. Приходится использовать самописные вещи для валидации или проводить проверку полей в самом handler.

  3. Из-за специфичной архитектуры невозможно говорить о микросервисах.

  4. В версии до 2.0 graphQl был старый и deprecated, и ты ничего не мог с этим поделать.

  5. Невозможно переписать handler для ошибок.

  6. Форум (community help) в целом заточен на вопросы frontend-части и для backend достаточно бесполезен.

Выводы

При работе с Payload следует учитывать, что могут возникнуть некоторые проблемы, когда мы хотим функционал чуть больший, чем представляется из коробки. Ограничения версий, самописный код может начать конфликтовать с тем, что есть в системе или могут возникнуть другие ситуации, описанные в статье. Но все эти минусы присущи не только Payload, а любым «коробочным решениям».

Если резюмировать весь опыт взаимодействия с Payload, то нужно отметить, что это действительно весьма удобный инструмент для создания прототипов и MVP. В нашем случае он позволил создать два крупных качественных MVP с большим количеством функционала за сжатые сроки.

© Habrahabr.ru