В этой статье обсуждаются стратегии обработки ошибок при работе с фреймворком Axum и написании REST API на Rust. Несмотря на то, что Axum является очень хорошо написанным фреймворком и имеет хорошие парадигмы, мы, как программисты, обязаны корректно и осмысленно обрабатывать ошибки в рамках фреймворка.

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

Общая обработка ошибок API

Axum предоставляет очень простой способ обработки ошибок. Принцип, который следует понимать, заключается в том, что приложение не может аварийно завершать работу в случае возникновения ошибки. Все ошибки должны быть Infallible .

Проще говоря, все ошибки – это ответы, которые можно обработать по протоколу HTTP.

Точно так же, как мы представляли бы объект JSON как ответ, мы можем смоделировать наши ошибки как объекты, которые могут быть предоставлены нашим клиентам — с правильными кодами ответа. В этом посте мы рассмотрим два разных способа построить это. Простой ответ о статусе с ошибками String. Для простоты мы начнем с текстовых ответов, которые могут быть отображены встроенным в AXUM средством визуализации ошибок StatusCode.

Настройка проекта

Давайте создадим новое приложение для этой демонстрации.

cargo new axum-error-handling-demo

Добавьте следующие зависимости, чтобы начать писать наши API.

Мы добавим простой обработчик, который ожидает параметр запроса и возвращает его в нашем ответе. Это как привет, мир с добавлением значения параметра запроса. Ниже приведено определение нашего приложения, которое отображает эту конечную точку в /hello.

Вызов нашего базового API

С этой настройкой мы можем запустить наш сервер ( cargo run ) и протестировать его на нашей локальной машине.

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

http://localhost:3000/hello?name=test

И мы увидели бы ответ с нашим именем в нем.

Теперь попробуйте вызвать этот API без передачи параметра запроса. Мы видим, что у нас есть следующий ответ сейчас.

http://localhost:3000/hello

И ответ, который мы видим,

Failed to deserialize query string: missing field `name`

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

Но приведенное выше сообщение раскрывает детали реализации приложения, что совсем не рекомендуется.

Решение

Чтобы решить эту проблему, мы можем использовать простой подход. Мы можем заставить нашу структуру принимать Option<String> , а не String Param. Таким образом, если значения нет, мы не получим сообщение об ошибке с внутренними данными.

Следующим шагом будет проверка входных данных, чтобы убедиться, что мы можем отправить настраиваемый ответ об ошибке нашим клиентам.

Пожалуйста, найдите обновленную структуру ниже:

Теперь попробуйте вызвать ту же конечную точку без параметра запроса. Вы должны увидеть красивое сообщение об ошибке, которое точно скажет вам, что может быть не так.

http://localhost:3000/hello 
Required Parameter name is missing within the request.

Ошибки JSON

До сих пор мы видели, как моделировать ошибки в среде Axum в виде простых строк.

Поскольку большинство API-интерфейсов REST написаны как API-интерфейсы JSON, давайте посмотрим, как мы можем моделировать ошибки в виде ответа в формате Json.

Чтобы смоделировать ошибки как JSON, нам нужно определить наши модели ошибок приложений. Мы создадим новый объект ApiError, который будет действовать как корневая ошибка. В нем мы сохраним код состояния http и добавим несколько вспомогательных методов для инициализации ошибок. Мы также используем библиотеку thiserror, которая помогает нам легко создавать собственные ошибки в Rust.

Преобразование ошибок как ответа

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

Как фреймворк, axum очень упрощает работу с ошибками. Вы можете думать об этом как об еще одном ответе JSON, если вызов был успешным. Кроме того, мы должны убедиться, что коды ответов Http настроены так, чтобы клиент мог предпринять необходимые действия.

Чтобы убедиться, что axum может понимать ApiError как тип ответа на ошибку, мы попробуем реализовать трейт IntoResponse для нашей структуры. Это сообщает axum, что это допустимый тип ошибки. Любая полезная нагрузка в этой ошибке будет переведена как HttpResponse с использованием сериализации Json.

Ниже приведена реализация нашей структуры ApiError.

Здесь вы можете видеть, что мы проанализировали код состояния, связанный с ошибкой, и сериализовали нашу структуру в ответ.

Таким образом, наши пользователи теперь могут получить предварительный просмотр всех ошибок в удобном формате json. Давайте реализуем обработчик и попробуем это. Обратите внимание, как меняется сигнатура метода для нашего API.

Тестирование API

Мы можем повторить наш предыдущий вызов с допустимым параметром запроса, и мы должны увидеть новый ответ с правильным результатом.

http://localhost:3000/hello?name=test
{ "greeting": "hello", "name": "test" }

Теперь попробуем без параметра запроса.

http://localhost:3000/hello?name=test
{
    "status_code": 400,
    "errors": [
        "Required Parameter name is missing within the request."
    ]
}

Заключение

В этом посте вы увидели очень простую, но мощную технику обработки ошибок во фреймворке Axum в Rust. Мы заметили, что сами определения наших обработчиков упростились, а наша структура ApiError гарантирует, что она знает, как отправить ответ пользователю. Первоначальная настройка этого проекта может быть обременительной, но после настройки вся обработка ошибок в приложении, без сомнения, стандартизирована. Эту структуру ApiError можно даже разделить в крейте и использовать в нескольких проектах Axum для обработки ошибок.

Первоначально опубликовано на https://shanmukhsista.com 10 октября 2022 г.