验证输入JSON
#api #go #休息

您将在这篇文章中看到的所有代码您可以检查here

在上一篇文章中,我们做了帖子方法来在我们的应用程序中创建书籍,在本文中,我们将在主持人层(或数据传输对象)中进行验证,该验证代表我们的REST API中的JSON输入。

在这种情况下,我们将使用一个验证器lib,可以帮助我们进行流程。

所以让我们安装lib

go get github.com/go-playground/validator/v10

在我们的情况下,我们需要在主持人层中添加一些标签,以解释我们将要验证的内容。

//cmd/http/presenter/book.go

type BookPersist struct {
    Title       string `json:"title" validate:"required"`
    Author      string `json:"author" validate:"required"`
    NumberPages int    `json:"numberPages" validate:"required"`
}

在我们的书本构造中,我们添加了一个validate标签,在我们的示例中,我们只添加了一个必需的值即可在我们的字段中转动所需值,但是您可以查看验证器文档以检查您可以使用的每个值。

,但我们需要更改代码中的某些位置,以不影响我们的处理程序或用户时期。

在这一刻,我们可以将JSON解码为在bindjson方法中的comepent.go文件中构造。让我们更新我们的bindjson,以检查我们的验证。

//cmd/http/helper/request.go

func BindJson(r *http.Request, destination interface{}) error {
    e := json.NewDecoder(r.Body).Decode(destination)
    if e != nil {
        return ErrDecodeJson
    }
    return validateJsonFields(destination)
}

func validateJsonFields(input interface{}) error {
    validator := validator.New()
    if err := validator.Struct(input); err != nil {
        return err
    }
    return nil
}

ValidateJsonFields将帮助我们集中每个通过此处的演示者/DTO的验证。

因此,验证器。new将实例化lib and validator.struct(...)将为我们做魔术,如果我们的JSON不尊重我们在验证标签中放置的验证字段,则将生成错误。<<<<<<<<<<<<<<<<<< /p>

bindjson将为每个解码称之调用此方法,请告诉您,如果您的struct不使用validation tag bindjson将继续工作,没有任何问题,好吧,

但是我们的应用程序不知道如何通过友好的消息将验证错误响应给我们的用户。为了解决我们需要再改变一个地方。是的,我们的DealWith(...)方法处理了我们的处理程序中的错误。因此,让我们改善我们的DealWith方法。

//cmd/http/helper/error.go

func DealWith(err error) HttpError {
    if ok, httpError := isValidationError(err); ok {
        return *httpError
    } else if errCode, ok := errorHandlerMap[err]; ok {
        return HttpError{Status: errCode, Description: err.Error()}
    } else {
        return HttpError{
            Status:      http.StatusInternalServerError,
            Description: "Internal error, please report to admin",
        }
    }
}

func isValidationError(err error) (bool, *HttpError) {
    v := &validator.ValidationErrors{}
    if errors.As(err, v) {
        validationErrors := HttpError{Status: http.StatusBadRequest, Description: ErrJsonValidation.Error()}
        for _, err := range err.(validator.ValidationErrors) {
            message := generateErrorMessage(err)
            validationErrors.Messages = append(validationErrors.Messages, message.Error())
        }
        return true, &validationErrors
    }
    return false, nil
}

func generateErrorMessage(err validator.FieldError) error {
    return fmt.Errorf("error: field validation for '%s' failed on the '%s' tag", err.Field(), err.Tag())
}

首先,我们将创建IsvalidationError(...),我们将检查是否从我们的新验证器lib产生了来自处理程序错误的错误。

我们迭代范围err。(validator.ValidationErrors),因为我们的struct可能会在每个字段中丢弃一个以上的错误,在此范围内,我们将错误附加到带有所有验证的消息。

生成越野(...)这只是导致明确消息的方法。

,在DealWith方法中,我们进行了新的检查
如果可以,则httperror:= iSvalidationError(err);好{...}
首先,这是非常重要的,因为验证错误不会被视为域错误,因此,我们不需要在ErrorHandLermap中注册ERRJSONVALIDATION。

现在,我们的应用程序知道如何处理验证器lib中的验证消息而无需更改任何处理程序或用户酶。

现在,我们将派遣一个卷曲来检查响应

curl --location 'http://localhost:8080/v1/books' \
--header 'Content-Type: application/json' \
--data '{
    "title": "title",
    "numberPages": 200
}'

{"description":"error validating json","messages":["error: field validation for 'Author' failed on the 'required' tag"]}

现在,我们的应用程序从主持人层中获取错误消息,并给我们的用户提供友好的消息。

在下一篇文章中,我们将开始配置我们的基础架构以添加Docker和Docker-Compose以将我们的内存存储库更改为PostgreSql。