Ошибка валидации рассматривается как ошибка декодирования в фреймворке Go Gin.

Вопрос или проблема

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

Вот мой текущий код:

func checkPostReq(ctx *gin.Context, req any) (string, error) {
    if err := ctx.ShouldBindJSON(req); err != nil {
        var validationErrs validator.ValidationErrors
        if errors.As(err, &validationErrs) {
            // Обработать ошибку валидации
            err = apperror.WrapValidationErr(validationErrs)
        } else {
            // Обработать ошибку декодирования
            err = apperror.ReqBodyDecodeFailed.Wrap(err, "не удалось декодировать тело запроса")
        }
        ctx.JSON(http.StatusBadRequest, apperror.ErrorResponse(ctx, err))
        return "", err
    }

    uidStr, err := checkUid(ctx)
    if err != nil {
        ctx.JSON(http.StatusUnauthorized, apperror.ErrorResponse(ctx, err))
        return "", err
    }

    return uidStr, nil
}

Когда я намеренно вызываю ошибку валидации, сообщение об ошибке выглядит так:

ОШИБКА "Key: 'CreatePostRequest.MainCategory' Error:Field validation for 'MainCategory' failed on the 'required' tag"

Но вместо того, чтобы рассматривать это как ошибку валидации, она улавливается как ошибка декодирования, и выполняется ветка ReqBodyDecodeFailed.

Вопросы:
Почему ошибка валидации улавливается как ошибка декодирования?
Есть ли лучший способ различать ошибки валидации и ошибки декодирования при использовании ShouldBindJSON?
Как я могу гарантировать корректную обработку ошибок валидации?
Заранее спасибо!

Ответ или решение

Когда вы используете библиотеку Gin для работы с валидацией входящих JSON-запросов, важно понимать, как обрабатываются ошибки декодирования и валидации. Давайте рассмотрим ваши вопросы подробнее.

Причина, по которой ошибка валидации рассматривается как ошибка декодирования

Ошибки, возникающие при декодировании JSON, обрабатываются в методе ShouldBindJSON. Если ваши структуры данных не соответствуют данным, приходящим от клиента, Gin не сможет корректно выполнить десериализацию, в результате чего может возникнуть ошибка, которая не всегда соответствует "чистой" ошибке декодирования. Ваша структура может иметь теги валидации, и если данные не соответствуют этим тегам (например, при отсутствии обязательных полей), то Gin может возвращать ошибку, которая не может быть четко классифицирована как ошибка декодирования, но тем не менее обрабатывается в этом контексте.

Как отличить ошибки валидации от ошибок декодирования

Для того чтобы более четко разделять ошибки валидации и декодирования, можно использовать библиотеку go-playground/validator, которая особенно хорошо интегрируется с Gin. Ошибка, которую вы получаете, указывает на то, что валидация произошла, но она все еще интерпретируется как ошибка декодирования.

Для того чтобы правильно обрабатывать эти ошибки, вам стоит изменить порядок обработки ошибок. Ниже приведен пример кода:

func checkPostReq(ctx *gin.Context, req any) (string, error) {
    // Попробуем привязать JSON
    if err := ctx.ShouldBindJSON(req); err != nil {
        // Обрабатываем только ошибки декодирования
        ctx.JSON(http.StatusBadRequest, apperror.ErrorResponse(ctx, apperror.ReqBodyDecodeFailed.Wrap(err, "failed to decode request body")))
        return "", err
    }

    // Валидация структуры
    validate := validator.New()
    if err := validate.Struct(req); err != nil {
        var validationErrs validator.ValidationErrors
        if errors.As(err, &validationErrs) {
            // Обработка валидационной ошибки
            err = apperror.WrapValidationErr(validationErrs)
            ctx.JSON(http.StatusBadRequest, apperror.ErrorResponse(ctx, err))
            return "", err
        }
    }

    // Получение UID
    uidStr, err := checkUid(ctx)
    if err != nil {
        ctx.JSON(http.StatusUnauthorized, apperror.ErrorResponse(ctx, err))
        return "", err
    }

    return uidStr, nil
}

Как корректно обрабатывать ошибки валидации

  1. Сначала следует вызывать ctx.ShouldBindJSON для выполнения декодирования.
  2. Обработайте ошибки декодирования. Если в процессе декодирования возникла ошибка, сразу возвращайте её.
  3. После успешного декодирования выполните валидацию с использованием validator. Если валидация не проходит, обрабатывайте и возвращайте ошибку валидации.

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

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

Оцените материал
Добавить комментарий

Капча загружается...