Разработка стабильного продукта, способного держать высокие нагрузки на разных серверах, — задача сложная и ресурсозатратная. Программист не может сфокусироваться только на бизнес-логике: сначала нужно настроить базу данных, спроектировать серверные API и многое другое.
Сложность многократно возрастает при работе в одиночку. Приходится самому реализовывать интерфейс на выбранном фреймворке, обеспечивать совместимость слоёв, собирать проект в образы Docker и разворачивать его в Kubernetes. Добавьте сюда настройку маршрутизации через Nginx и проектирование системы по принципам чистой архитектуры — и получится крайне трудоёмкий процесс.
Поэтому во многих языках активно внедряют инструменты для автоматизации рутины (бойлерплейта), позволяя сосредоточиться на уникальном коде. Например, в Go есть библиотека oapi-codegen: вы описываете контракт в формате Swagger, а по нему автоматически генерируется код сервера. Такой формат упрощает интеграцию фронтенда и бэкенда и делает изменения логики менее болезненными — достаточно обновить описание в Swagger-файле и перегенерировать сервис.
Подобные подходы к систематизации повторяющихся задач появляются повсеместно. Главная цель — сделать интеграцию предсказуемой и исключить ситуацию, когда разработчику приходится десятки раз переписывать и тестировать одно и то же ради идеальной совместимости. И в этой сфере есть свой лидер — Ash!
ㅤ
ㅤ
🙏 Благодарности
Хочу выразить глубокую признательность Заку Даниэлю и всем, кто отреагировал на мою предыдущую статью об Ash (Ash Framework: Знакомство) и поделился ею. Ваша поддержка дала огромный заряд энергии и мотивации и подтвердила, что сообщество Ash — потрясающее!
ㅤ
📖 Предисловие
В этом материале намеренно не будет практическое руководство в полном объёме по указанным темам, так как полагаемся на вашу любознательность. Несмотря на желание охватить всё, я не смогу в одной статье описать всю практическую сторону данных фреймворков и научить вас всему и сразу. Вместо этого я поделюсь с вами информацией и задам направление для размышлений, что и является основной целью данной публикации. Для более глубокого погружения в работу этих библиотек я рекомендую вам начать создавать на их основе собственные проекты — именно такой подход когда-то помог мне лучше всего разобраться в их устройстве. Помните, что главным наставником для вас станет практика, поэтому успехов в её освоении!
Важно: цель статьи — вовсе не уговорить вас использовать Ash повсеместно и постоянно!
ㅤ
ㅤ
🧐 Что предлагает экосистема Ash
Если вы знакомы с Elixir и Phoenix, то знаете, что фреймворк уже содержит встроенные механизмы для упрощения разработки. Один из них — LiveView. Он позволяет отказаться от классического разделения на API-бэкенд и отдельный JavaScript-фронтенд: интерфейс пишется прямо внутри приложения. Это ускоряет разработку и удобно бэкенд-программистам, работающим без фронтенд-команды. Для простых и средних проектов путь с LiveView отлично подходит, но при создании масштабных систем код рискует превратиться в «спагетти», где трудно отслеживать зависимости между компонентами и находить обработчики вроде def handle_params/3.
А как быть, если нужен качественный обособленный фронтенд, но вы устали каждый раз заново писать шаблонный REST-интерфейс и настраивать связь? Ответ — освоить возможности Ash. О них и поговорим.
ㅤ
ㅤ
😮 REST с AshJsonApi: новый подход
Стандартная практика подразумевает фиксацию контракта между фронтендом и бэкендом не только на словах, но и документально — обычно через Swagger. В нём описывают структуры данных и методы API, после чего документация передаётся команде интерфейса. Любые изменения требуют осторожности, чтобы не сломать совместимость. Даже базовая настройка такого подхода стоит немалых усилий: нужно интегрировать библиотеку генерации, создать конфигурации по спецификации OpenAPI (Swagger) и вручную описать конечные точки (endpoints). Если речь о переписывании существующего проекта, процесс легко занимает больше рабочего дня.
AshJsonApi предлагает альтернативу. Главное преимущество — вам больше не нужно предварительно писать спецификацию в YAML/JSON и генерировать из неё код. Для старта достаточно готового домена ресурсов и подключённого расширения AshJsonApi.
Создать новый проект с поддержкой этого инструмента можно прямо на главной странице портала Ash через конструктор. Если проект на Ash уже есть, добавить функциональность можно одной командой:
mix igniter.install ash_json_api
В процессе установки система задаёт уточняющие вопросы (Y/N). Можно соглашаться со всеми предложениями или изучить каждый пункт и решить самостоятельно. После установки останется выполнить несколько простых шагов.
Настройка ресурса для работы с JSON:API
Чтобы ресурсы стали доступны через API, подключите расширение AshJsonApi.Resource. Это позволит автоматически сгенерировать эндпоинты на основе определений домена. Добавьте AshJsonApi.Resource в список extensions и задайте имя ресурса в параметре type:
defmodule CourseHub.Courses.Lesson do
use Ash.Resource, extensions: [AshJsonApi.Resource]
# Активация генерации эндпоинтов
json_api do
type "lesson"
end
actions do
defaults [:read, :create, :destroy, :update]
action :list_lessons_allowed, :map do
run fn _input, _ctx ->
allowed_courses = %{"go" => "Golang", "elixir" => "Elixir", "rust" => "Rust"}
{:ok, allowed_courses}
end
end
end
end
Параметр type определяет имя ресурса в пространстве имён JSON:API. Он используется преимущественно для документации (например, в Swagger или Redoc) и позволяет группировать методы по тегам.
Далее опишите маршруты в домене, указав пути и связав их с конкретными действиями ресурса:
defmodule CourseHub.Courses do
use Ash.Domain, extensions: [AshJsonApi.Domain]
json_api do
routes do
base_route "/lessons", CourseHub.Courses.Lesson do
index :read, description: "Получение списка лекций"
get :read, primary?: true, description: "Получение одной лекции"
post :create, description: "Создание лекции"
patch :update, description: "Изменение лекции"
delete :destroy, description: "Удаление лекции"
# Путь относителен base_route, итоговый эндпоинт: /lessons/allowed
route :get, "/allowed", :list_lessons_allowed,
description: "Получение списка разрешённых лекций"
end
end
end
end
Выполнив эти шаги, вы получите шесть полностью функциональных эндпоинтов. Вся логика теперь связана с вашими actions внутри доменной модели. Отдельные Swagger-файлы или ручное определение маршрутов не нужны: изменение логики action в коде автоматически отражается на поведении соответствующего API-эндпоинта.
Ключевые достоинства AshJsonApi
Единый подход и предсказуемость
Основное преимущество — строгая согласованность приложения. При переходе на другой тип контракта (например, GraphQL) не придётся переписывать бизнес-логику. Поскольку AshJsonApi работает поверх ваших actions, вы застрахованы от ситуации, когда изменения в коде не отразились в одном из интерфейсов: вся логика инкапсулирована в action, который вы «раздаёте» разным контрактам. Это заметно ускоряет разработку — по личным оценкам, готовый продукт получается примерно в пять раз быстрее. Для автоматизации можно воспользоваться командой:
mix ash.patch.extend CourseHub.Courses.Lesson json_api
Указав адрес ресурса, вы позволите AshJsonApi автоматически сгенерировать всю обвязку для работы с API.
Работа с данными: фильтрация, сортировка и связи
Как бэкенд-разработчик, я раньше тратил много времени на рутинную реализацию фильтров и сортировок, вручную составляя SQL с LIMIT, OFFSET и WHERE. AshJsonApi избавляет от этого: фильтрация и упорядочивание выполняются автоматически. Фронтенду достаточно указать нужные поля и условия прямо в запросе. Это кардинально упрощает взаимодействие команд: фронтенд формирует запросы к данным самостоятельно, не отвлекая бэкенд. При этом все вычисления происходят на сервере, поэтому клиент не несёт лишней нагрузки — он лишь описывает желаемую схему данных. Полный список параметров есть в официальной документации. Пример запроса:
GET /courses/1?include=lessons&included_page[lessons][limit]=10&included_page[lessons][offset]=20
Запрос возвращает информацию о курсе и подгружает связанные лекции с заданной пагинацией. Ответ приходит в формате application/vnd.api+json — это стандартизированная спецификация (подробнее на jsonapi.org), которая структурирует JSON для предсказуемой работы.
Пример ответа:
{
"data": {
"id": "1",
"type": "course",
"attributes": {
"title": "My Course!"
},
"relationships": {
"lessons": {
"data": [
{"id": "1", "type": "lessons"},
{"id": "2", "type": "lessons"}
],
"links": {
"self": "/courses/1/relationships/lessons",
"related": "/courses/1/lessons",
"first": "/courses/1?include=lessons&included_page[lessons][limit]=10",
"next": "/courses/1?include=lessons&included_page[lessons][limit]=10&included_page[lessons][offset]=10",
"prev": null,
"last": "/courses/1?include=lessons&included_page[lessons][limit]=10&included_page[lessons][offset]=40"
},
"meta": {
"limit": 10,
"offset": 0,
"count": 50
}
}
}
},
"included": [
{
"id": "1",
"type": "lessons",
"attributes": {
"description": "Lessons about Elixir 1!"
}
},
{
"id": "2",
"type": "lessons",
"attributes": {
"description": "Lessons about Elixir 2!"
}
}
]
}
Заключение и личный опыт
Подводя итог, поделюсь опытом. На текущем проекте создание REST-эндпоинтов заняло всего 20–30 минут. Основное время ушло на кастомизацию отображения документации в Redoc — вот это оказалось довольно трудоёмким (в отличие от генерации самого API). Если решите использовать Redoc, будьте готовы вручную переписывать его блоки ради красивого вывода ответов и примеров.
В остальном инструмент показал себя отлично: великолепная гибкость, кастомизируемая обработка ошибок, тонкое управление доступом к эндпоинтам. Если цель — построить удобный и мощный REST API, AshJsonApi отличный выбор.
ㅤ
ㅤ
🙂↕️ AshGraphQL
С этой библиотекой возможны сложности: не так много людей вообще работали с GraphQL. Поэтому сначала дам вводную — освежить память или узнать, что это такое, — а потом посмотрим саму библиотеку.
Что такое GraphQL
GraphQL — это язык запросов для API и рантайм для их исполнения. Клиент сам описывает, какие данные ему нужны, а сервер возвращает ровно эту форму. Контрактом служит строго типизированная схема.
Фундаментальные принципы
Взаимодействие идёт через единый endpoint (обычно POST /graphql). Логика строится вокруг графа типов. Запрос имеет иерархическую структуру, и ответ сервера в точности её повторяет. Это решает проблемы over-fetching и under-fetching.
Виды операций
- Query — операции на чтение (идемпотентны).
- Mutation — операции на изменение данных (выполняются последовательно).
- Subscription — подписка на поток событий в реальном времени (через WebSocket).
Схема и резолверы
Центральный элемент — схема, описываемая на SDL. Она служит источником истины и позволяет проводить интроспекцию. Каждое поле сопоставляется с резолвером — функцией, возвращающей значение. Сервер обходит дерево запроса и вызывает резолверы для каждого поля.
Сложности
- Проблема N+1. Резолверы работают независимо, и без оптимизации (батчинга) это приводит к множеству запросов к базе
- Кэширование. Стандартные HTTP-механизмы (CDN, ETag) не работают, так как всё идёт через POST. Требуется нормализованный кэш на клиенте
- Безопасность. Клиент может отправить глубоко вложенный запрос, перегружающий базу. Нужны ограничение глубины и анализ сложности
-
Ошибки. Сервер почти всегда возвращает статус
200, а сами ошибки помещаются в массивerrorsрядом с частичными данными. Это ломает мониторинг, основанный на кодах состояния HTTP - Инфраструктура. Загрузка файлов, rate limiting и наблюдаемость требуют отдельного инфраструктурного слоя
Где эффективен
Технология оправдывает себя при множестве разнообразных клиентов со сложными требованиями к данным. Для одного клиента с простыми ресурсами проще взять REST. Для внутреннего межсервисного взаимодействия с жёсткими контрактами и минимальной задержкой лучше подходит gRPC.
Что представляет собой AshGraphQL
Несмотря на то что GraphQL пока уступает в популярности другим подходам, его интеграция с Ash сделана очень качественно. Технологию легко внедрить в проекты на базе Ash.
Для начала добавьте библиотеку в проект:
mix igniter.install ash_graphql
Затем в модуле схемы укажите используемые домены:
use AshGraphql, domains: [Your.Domain1, Your.Domain2]
Настройка ресурсов и доменов
Чтобы ресурс стал доступен через GraphQL, подключите расширение AshGraphql.Resource и опишите базовый блок конфигурации:
defmodule CourseHub.Courses.Lesson do
use Ash.Resource,
extensions: [
AshGraphql.Resource
]
graphql do
type :lesson
end
# ... остальная логика ресурса
end
В модуле домена определите операции (ручки) через расширение AshGraphql.Domain:
defmodule CourseHub.Courses do
use Ash.Domain,
extensions: [
AshGraphql.Domain
]
graphql do
queries do
get CourseHub.Courses.Lesson, :get_lesson, :read
read_one CourseHub.Courses.Lesson, :most_popular_lesson, :most_popular
list CourseHub.Courses.Lesson, :list_lessons, :read
end
mutations do
create CourseHub.Courses.Lesson, :create_lesson, :create
update CourseHub.Courses.Lesson, :update_lesson, :update
destroy CourseHub.Courses.Lesson, :destroy_lesson, :destroy
end
end
end
Описывать эти ручки можно не только в модуле домена, но и прямо внутри ресурса.
Кроме того, вы можете создавать собственные действия для кастомных ответов. Пример:
graphql do
type :lesson
queries do
action :random_lesson, :random_lesson
end
end
actions do
action :random_lesson, {:array, :struct} do
constraints items: [instance_of: __MODULE__]
run fn _input, _context ->
# возвращаем список структур, как объявлено в типе действия
Ash.read(__MODULE__)
end
end
end
Генерация схемы SDL
Как и в AshJsonApi (где Swagger генерируется автоматически после правок), схема GraphQL обновляется схожим образом. Пропишите путь для сохранения в use AshGraphql через generate_sdl_file:. Файл будет автоматически генерироваться при каждом запуске mix ash.codegen (если включён auto_generate_sdl_file?: true):
use AshGraphql,
domains: [Domain1, Domain2],
generate_sdl_file: "priv/schema.graphql",
auto_generate_sdl_file?: true
Создание подписок (Subscriptions)
Можно настроить получение данных в реальном времени через механизм подписок. Для этого используется конфигурация Absinthe:
# в файле схемы Absinthe
subscription do
field :field, :type_name do
config(fn
_args, %{context: %{current_user: %{id: user_id}}} ->
{:ok, topic: user_id, context_id: "user/#{user_id}"}
_args, _context ->
{:error, :unauthorized}
end)
resolve(fn args, _, resolution ->
AshGraphql.Subscription.query_for_subscription(
YourResource,
YourDomain,
resolution
)
|> Ash.Query.filter(id == ^args.id)
|> Ash.read(actor: resolution.context.current_user)
end)
end
end
Мониторинг
Для глубокого погружения рекомендую официальное руководство по мониторингу Ash. Здесь кратко опишем механизмы трассировки и события телеметрии, которые становятся доступны с этим расширением.
Можно определить собственный трассировщик на уровне домена — его настройки будут иметь приоритет над глобальным параметром config :ash, :tracer:
graphql do
tracer MyApp.Tracer
end
Трассировка (Traces)
Операции резолверов GraphQL и базовых пакетных загрузчиков данных оборачиваются в диапазоны (spans) с соответствующими именами. Для удобства к ним добавляется метаданное source: :graphql, что позволяет фильтровать или комментировать эти данные в системе мониторинга.
Телеметрия (Telemetry)
Модуль AshGraphql публикует события телеметрии, каждое из которых сопровождается суффиксами :start и :stop. События начала (:start) содержат измерение system_time, а события завершения (:stop) — system_time и длительность выполнения duration. Все временные показатели представлены в нативных единицах времени.
Список генерируемых событий:
-
[:ash, <имя_домена>, :gql_mutation]— выполнение мутации. Для детализации используйте метаданныеresource_short_nameиmutation(илиaction) -
[:ash, <имя_домена>, :gql_query]— выполнение запроса. Для детализации используйте метаданныеresource_short_nameиquery(илиaction) -
[:ash, <имя_домена>, :gql_relationship]— разрешение связи. Для детализации используйте метаданныеresource_short_nameиrelationship -
[:ash, <имя_домена>, :gql_calculation]— разрешение вычисления. Для детализации используйте метаданныеresource_short_nameиcalculation -
[:ash, <имя_домена>, :gql_relationship_batch]— пакетное разрешение связей загрузчиком данных. Для детализации используйте метаданныеresource_short_nameиrelationship -
[:ash, <имя_домена>, :gql_calculation_batch]— пакетное разрешение вычислений загрузчиком данных. Для детализации используйте метаданныеresource_short_nameиcalculation
Отзыв
Честно говоря, я нечасто прибегал к такому формату взаимодействия, но из того немногого опыта, что у меня есть, скажу одно — это действительно удобно.
ㅤ
ㅤ
😳 AshTypescript — скрытая жемчужина
Мы уже познакомились с AshJsonApi и AshGraphQL, и это был полезный опыт. Эти два подхода — своего рода индустриальный стандарт веб-разработки, и особых сюрпризов для опытных специалистов в них нет. Но у Ash есть «козырная карта» — AshTypescript.
Представьте, что вы хотите взаимодействовать с фронтендом с типобезопасностью уровня gRPC, сохраняя структуру эндпоинтов как в AshJsonApi и гибкость работы с данными как в AshGraphQL. Именно это и решает AshTypescript.
Принцип работы
- Определение структуры. Вы описываете домен и ресурсы, указывая нужные действия (actions) и атрибуты
-
Подключение расширений. В ресурс добавляется
AshTypescript.Resource, а в домен —AshTypescript.Rpc -
Настройка ресурса. В блоке
typescriptвнутри ресурса задаётся его имя для генерации
defmodule CourseHub.Courses.Lesson do
use Ash.Resource,
domain: CourseHub.Courses,
extensions: [AshTypescript.Resource] # Подключаем расширение
# Задаём имя типа для сгенерированного RPC-файла
typescript do
type_name "Lesson"
end
# Стандартные CRUD-действия
actions do
defaults [:read, :create, :update, :destroy]
end
# Описываем атрибуты ресурса
attributes do
uuid_primary_key :id
attribute :title, :string, allow_nil?: false
attribute :description, :string, default: "Какой-то текст!"
end
# Описываем связь с Course
relationships do
belongs_to :course, CourseHub.Courses.Course
end
end
- Привязка RPC-методов. В модуле домена вы определяете, какие методы будут доступны фронтенду, и связываете их с действиями ресурса.
defmodule CourseHub.Courses do
use Ash.Domain, extensions: [AshTypescript.Rpc]
# Публичные RPC-методы для фронтенда
typescript_rpc do
resource CourseHub.Courses.Lesson do
rpc_action :list_lessons, :read
rpc_action :create_lesson, :create
rpc_action :get_lesson, :get
rpc_action :delete_lesson, :destroy
rpc_action :update_lesson, :update
end
end
end
-
Генерация кода. Запустив
mix ash_typescript.codegen(или общуюmix ash.codegen), вы получите сгенерированные файлы по пути из конфигурации. Настройки лежат вconfig/config.exs:
config :ash_typescript,
ash_domains: [
Backend.CourseHub
],
output_file: "assets/js/ash_rpc.ts", # Путь для сохранения сгенерированного кода
run_endpoint: "/rpc/run", # Эндпоинт для отправки запросов
validate_endpoint: "/rpc/validate", # Эндпоинт для валидации данных по схеме
input_field_formatter: :camel_case, # Формат имён полей на входе
output_field_formatter: :camel_case, # Формат имён полей на выходе
require_tenant_parameters: false, # Мультитенантность
generate_zod_schemas: true, # Генерация схем для Zod
generate_phx_channel_rpc_actions: false,
generate_validation_functions: true,
zod_import_path: "zod",
zod_schema_suffix: "ZodSchema",
phoenix_import_path: "phoenix"
Zod — библиотека для описания и проверки структуры данных. Она позволяет создавать схемы и автоматически валидировать по ним входящие данные.
Ключевые преимущества Zod:
- Ориентированность на TypeScript — автоматически выводит типы
- Интуитивно понятный и легко читаемый API
- Поддержка сложных правил валидации (объединения типов, пересечения, уточнения)
- Высокая производительность и минимальный вес
Начиная с новых версий, AshTypescript генерирует не один монолитный файл, а несколько: помимо ash_rpc.ts появляются общие типы (ash_types.ts) и схемы Zod (ash_zod.ts), которые импортируются из общего места.
В итоге вам остаётся лишь передать сгенерированные файлы на фронтенд. Разработчики клиента просто вызывают методы, например listLessons(), без ручного описания API. Это делает интеграцию невероятно простой и удобной.
Механизмы сортировки, фильтрации и проекции полей
В стандартной серверной разработке приходится вручную конструировать SQL-запросы для сортировки, фильтрации и выборки, чтобы избежать избыточной передачи данных. В AshTypescript реализованы те же возможности, что и в AshJsonApi, — гибко и типобезопасно:
// CREATE
const createLessonResponse = await createLesson({
fields: ["id", "title"],
input: { title: "Elixir lesson about Ash", priority: "very high!" },
headers
});
if (!createLessonResponse.success) {
console.error("Create failed:", createLessonResponse.errors);
return;
}
const lessonId = createLessonResponse.data.id;
// READ (single)
const getLesson = await getLesson({
fields: ["id", "title", "description", { course: ["name"] }],
input: { id: lessonId },
headers
});
// READ (list)
const lessons = await listLessons({
fields: ["id", "title"],
headers
});
// UPDATE
const updateLessonResult = await updateLessson({
fields: ["id", "title"],
identity: lessonId,
input: { title: "Yoo chill im just a vessel!" },
headers
});
// DELETE
const deleteLessonResponse = await deleteLesson({
identity: lessonId,
headers
});
Преимущества использования AshTypescript
- Гарантия целостности контракта. Не нужно беспокоиться о рассинхроне интерфейса, как это бывает с «ручным» gRPC. Единственный источник истины — генератор .ts-файлов
-
Автоматизация создания API. Отпадает ручное написание методов и эндпоинтов. Достаточно описать ресурс и
typescript_rpcв домене и дать методам уникальные имена - Минимизация шаблонного кода. Встроенные инструменты для сортировки, фильтрации и выборки полей (select/проекции) делают работу бесшовной
- Простая интеграция с другими командами. Сгенерированные файлы (ash_rpc.ts, ash_types.ts, ash_zod.ts) можно передать коллегам — они начнут работу немедленно, не тратя время на изучение документации
Впечатления
Узнав об этом способе организации взаимодействия между сервером и клиентом, я вновь испытал энтузиазм к программированию. Ручное написание эндпоинтов монотонно, а описание схем для GraphQL отнимает много времени. Декларативное же описание actions на бэкенде и простой вызов методов на фронтенде — это быстро и удобно. Такой подход убирает до 80% лишнего кода и многократно ускоряет разработку.
ㅤ
ㅤ
🧮 Сравнение трёх подходов
У всех трёх способов один фундамент — ваши actions. Меняется только «витрина», через которую логика выходит наружу. Отсюда и главный вывод: выбор способа не запирает вас в нём навсегда — при необходимости можно добавить второй контракт поверх той же логики.
| Критерий | AshJsonApi (REST / JSON:API) | AshGraphQL | AshTypescript |
|---|---|---|---|
| Тип контракта | REST по стандарту JSON:API | GraphQL-схема (SDL) | Сгенерированные .ts-файлы (RPC) |
| Источник истины | ваши actions + автоген OpenAPI | ваши actions + автоген SDL | ваши actions + автоген TypeScript |
| Как клиент задаёт запрос | query-параметры (filter, sort, include) |
GraphQL-запрос с деревом полей | типизированные вызовы (fields, filter, sort) |
| Гибкость выборки | высокая | максимальная | высокая |
| Индустриальный стандарт | да, повсеместно | да, но нишевый | нет, специфичен для стека Ash + TS |
| Типобезопасность на фронте | через кодоген из OpenAPI | через кодоген из схемы | нативная, из коробки |
| Реалтайм | нет из коробки | да (subscriptions) | да (Phoenix channels) |
| HTTP-кэширование | работает (GET) | затруднено (POST) | зависит от реализации |
| Порог входа на фронте | низкий | средний/высокий | низкий (для TypeScript-команд) |
| Идеально для | публичные и внешние API | много разных клиентов со сложными запросами | full-stack Elixir + TypeScript |
Как выбирать на практике:
- AshJsonApi — когда нужен привычный REST, публичный или внешний API, кэширование на уровне HTTP и максимальная совместимость с любыми клиентами. Самый «нейтральный» выбор
- AshGraphQL — когда клиентов много и у них разные, часто вложенные требования к данным, а под-/пере-выборка (over/under-fetching) реально мешает. Готовьтесь платить за это батчингом против N+1, ограничением сложности запросов и клиентским кэшем
- AshTypescript — когда и бэкенд, и фронтенд ваши, и фронтенд на TypeScript. Даёт сквозную типобезопасность без ручного контракта: переименовали поле в Elixir — сразу получили ошибку компиляции в TS
Если сомневаетесь и клиент один и относительно простой — начните с AshJsonApi. Если позже понадобится GraphQL или типобезопасный RPC, вы просто добавите ещё один контракт поверх тех же actions, не переписывая логику.
ㅤ
ㅤ
😴 Заключение
Мир Ash даёт не просто удобный формат работы с БД и отсутствие бойлерплейта — он позволяет делать приложения быстро, качественно и с удовольствием. На полное освоение этих методов уйдёт чуть больше времени, но оно окупится не раз и здорово поможет в ваших проектах. Успехов!
ㅤ
ㅤ
🥴 От автора
Спасибо большое за интерес к этой статье! Надеюсь, она помогла разобраться, что представляет собой AshJsonApi, AshGraphQL, AshTypescript и зачем они используются!
Если эта статья пришлась вам по душе и хочется ещё материалов такого плана, присоединяйтесь ко мне в моём телеграм-канале, где выкладываю обзоры книг, публикации по Elixir, переводы технической литературы и интересные новости!
Top comments (0)