Возврат доменных ошибок через union-типы в GraphQL требует корректной обработки сценариев, когда один из источников данных (фидов) не возвращает ожидаемую структуру. Ошибка возникает, если система пытается сериализовать объект ошибки как тип данных, который не предусмотрен схемой, или если обработчик игнорирует исключение на уровне источника. Решение строится на перехвате ошибок до их выхода в клиент и явной маппинге структуры исключения в один из типов union.
Понимание природы ошибки при работе с union-типами
Union-тип в GraphQL позволяет вернуть данные из нескольких источников (фидов) под одним полем. Например, поле `product` может возвращать объект типа `ProductA`, `ProductB` или ошибку `Error`. Проблема возникает, когда один из фидов падает с исключением, которое не соответствует ни одному из ожидаемых типов union.
Если код сервера просто выбрасывает исключение (throw), GraphQL-сервер не может корректно сериализовать ответ, так как тип исключения неизвестен клиенту. Клиент получает ошибку 500 или пустой ответ вместо данных. Это нарушает контракт API и приводит к падению фронтенда.
Корректный подход требует, чтобы каждый источник данных гарантированно возвращал объект, соответствующий одному из типов union. Если источник не может вернуть данные в нужном формате, он должен обернуть ошибку в специальный тип ошибки, который уже зарегистрирован в схеме.
Шаг 1: Анализ структуры схемы и определение типов
Начните с проверки схемы GraphQL. Определите все типы, входящие в union-поле. Например, `union SearchResult = Product | Ad | Error`.
Проверьте, как каждый источник данных (фид) связан с этими типами. Убедитесь, что для каждого источника есть явное определение того, какой тип он должен возвращать при успехе и какой — при ошибке.
Если в схеме нет типа ошибки, добавьте его. Тип ошибки должен содержать поля `message`, `code` и `details`. Это позволит клиенту понять причину сбоя без необходимости парсить стек вызовов.
Шаг 2: Перехват ошибок на уровне источника
Для каждого источника данных реализуйте логику перехвата исключений. Если запрос к фиду падает, не выбрасывайте исключение напрямую в ответ GraphQL.
Создайте фабрику объектов ошибок. При возникновении исключения в источнике создайте объект типа `Error`, заполнив поля `message` текстом ошибки и `code` кодом (например, `FEED_TIMEOUT`).
Пример логики на псевдокоде: если `feedResponse.success === false`, то вернуть `{ __typename: 'Error', message: feedResponse.error }`. Это гарантирует, что ответ всегда будет валидным объектом union-типа.
Шаг 3: Настройка обработчиков ошибок для каждого источника
Настройте глобальные или локальные обработчики ошибок для каждого фидового соединения. Убедитесь, что они возвращают структуру данных, совместимую с типом `Error` в union.
Используйте try-catch блоки вокруг вызовов источников. В блоке catch создайте объект ошибки и верните его как часть ответа GraphQL.
Не игнорируйте ошибки. Если ошибка возникает, она должна быть включена в ответ запроса, чтобы клиент мог отобразить пользователю соответствующее сообщение.
Шаг 4: Тестирование сценариев ошибок
Проведите тесты, имитирующие сбои источников. Отключите один из фидов и выполните запрос, который должен вернуть данные из другого источника.
Проверьте, что ответ содержит объект типа `Error` с правильными полями, а не сырой стек вызовов или пустой объект.
Используйте инструменты отладки GraphQL (например, GraphiQL) для просмотра структуры ответа. Убедитесь, что поле `__typename` указывает на тип ошибки.
Шаг 5: Валидация возвращаемых данных
Реализуйте валидацию на уровне сервера перед отправкой ответа. Проверьте, что каждый объект в ответе соответствует одному из типов union.
Если структура ответа не соответствует схеме, выбросите ошибку 400 или 500 с понятным сообщением о несоответствии контракта API.
Валидация должна быть строгой: клиент должен всегда получать данные, которые он может обработать без дополнительных проверок.
Шаг 6: Оптимизация производительности обработки ошибок
Избегайте тяжелых операций внутри обработчиков ошибок. Создание объекта ошибки должно быть быстрым и не требовать внешних запросов.
Используйте кэширование результатов обработки ошибок, если они повторяются часто. Например, если ошибка связана с таймаутом сети, можно вернуть предзаготовленный объект ошибки.
Минимизируйте время обработки исключений за счет эффективной логики и избегания лишних вычислений.
Шаг 7: Документирование изменений
Обновите документацию API после внесения изменений в обработку union-типов. Укажите, какие типы ошибок могут возвращаться и при каких условиях.
Убедитесь, что все разработчики знают о новых правилах работы с ошибками в union-типах.
Документируйте примеры запросов и ответов, включая случаи с ошибками.
Вопросы и ответы
Что делать, если один из источников данных всегда возвращает ошибку?
Если источник постоянно недоступен, настройте его так, чтобы он возвращал объект типа `Error` с кодом `SOURCE_UNAVAILABLE`. Клиент должен уметь обрабатывать такие ошибки и переключаться на альтернативные источники данных.
Как избежать дублирования ошибок в ответе GraphQL?
Убедитесь, что каждый источник возвращает только один объект в union-поле. Если несколько источников падают одновременно, выберите приоритетный источник или верните агрегированную ошибку с кодом `MULTIPLE_SOURCES_FAILED`.
Можно ли использовать сырые исключения вместо объектов ошибок?
Нет. Сырые исключения не соответствуют схеме GraphQL и приведут к ошибкам сериализации. Всегда оборачивайте исключения в объекты типов union, зарегистрированных в схеме.
По теме
- Как искать потенциальных клиентов через технические ошибки сайтов
- Ошибки интернет-магазина, которые мешают SEO и продажам
// Пример обработчика ошибки для источника данных
async function handleFeedError(feedResponse: FeedResponse): Promise<SearchResult> {
if (!feedResponse.success) {
return {
__typename: 'Error',
message: feedResponse.error,
code: 'FEED_TIMEOUT'
};
}
return feedResponse.data as SearchResult;
}


