如何使用 Kotlin 在 Quarkus 中正确验证 REST 请求?
How do I correctly validate a REST request in Quarkus using Kotlin?
我目前正在使用 Kotlin 在 Quarkus 中创建一个应用程序。我正在尝试使用 RestEasy、Panache 和 Hibernate 创建一个简单的用户端点。我现在的挑战是异常处理没有正确完成。我想在请求无效时向用户显示正确且易于理解的消息。
这是我的 createUser POST 请求的用户资源:
@POST
@Transactional
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
fun createUser(@Valid user: User) : CreateUserResponse =
try {
userRepository.persist(user)
CreateUserSuccess(user)
} catch (e: Exception) {
CreateUserFailure(e)
}
这是我的用户实体:
@Entity
data class User (
@Id
@GeneratedValue(generator = "UUID")
var id: UUID? = UUID.randomUUID(),
@NotBlank
var fullName: String,
@Email
@NotBlank(message = "email may not be blank")
var email: String,
@CreationTimestamp
var createdAt: LocalDateTime? = null,
@UpdateTimestamp
var updatedAt: LocalDateTime? = null,
)
为了完整起见,这是我的 UserRepository:
@ApplicationScoped
class UserRepository : PanacheRepository<User>
当我确定请求有效时,创建用户确实有效。但我也想确保无效请求在请求无效时得到很好的处理。这是当我点击 createUser 端点时我现在得到的响应:
com.fasterxml.jackson.databind.exc.ValueInstantiationException: Cannot construct instance of
`com.fortuneapp.backend.application.domain.core.models.entities.User`, problem: Parameter specified as non-null is null:
method com.fortuneapp.backend.application.domain.core.models.entities.User.<init>, parameter email
at [Source: (io.quarkus.vertx.http.runtime.VertxInputStream); line: 3, column: 1]
我在这里错过了什么?
您遇到了属性的可空性问题,正如您所看到的,即使您正在定义 var
属性,其中一些属性不可为空 ?
所以因为您正在反序列化一个 json 消息,其余服务的输入,Jackson 无法创建模型的新实例 class user
因为某些必填字段不存在。
这类似于您尝试创建新对象但未在构造函数中提供所需参数的情况。
这里有一些使用 kotlin、Jax-RS 和 Hibernate-Panache 的建议 https://quarkus.io/guides/kotlin。
您尝试归档的内容完全有可能,但如果您想将实体用作请求主体,则必须使所有字段都可为空,否则底层 Json 序列化程序将无法创建模型的新实例以通过 @Valid
验证并生成约束违规报告。
这里有一些选择。
- 您可以创建一个所有属性都可为空的数据 class,这样您就可以确保所有 javax 验证注释都能够被检查,因为请求将能够被反序列化。然后将此对象映射到您的模型实体 class。您可以将此 class 视为 DTO,因为最后您将通过层边界移动数据并将您的服务合同与您的实体模型实现解耦,这往往很方便。
- 尽管 javax.validation 约束注释的使用非常方便,但您可以注入验证器并检索约束违规和 return 具有约束违规的自定义数据 class以比默认报告更具可读性的方式,在 resteasy 的反应版本中,quarkus 不支持默认报告。
如果还有疑问我可以举个例子
将您的字段设置为可为空,初始化它们并将 @field:
放在注释之前,它将起作用。
@Entity
data class User (
@Id
@GeneratedValue(generator = "UUID")
var id: UUID? = UUID.randomUUID(),
@field:NotBlank
var fullName: String = null,
@field:Email
@NotBlank(message = "email may not be blank")
var email: String = null,
...
我目前正在使用 Kotlin 在 Quarkus 中创建一个应用程序。我正在尝试使用 RestEasy、Panache 和 Hibernate 创建一个简单的用户端点。我现在的挑战是异常处理没有正确完成。我想在请求无效时向用户显示正确且易于理解的消息。
这是我的 createUser POST 请求的用户资源:
@POST
@Transactional
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
fun createUser(@Valid user: User) : CreateUserResponse =
try {
userRepository.persist(user)
CreateUserSuccess(user)
} catch (e: Exception) {
CreateUserFailure(e)
}
这是我的用户实体:
@Entity
data class User (
@Id
@GeneratedValue(generator = "UUID")
var id: UUID? = UUID.randomUUID(),
@NotBlank
var fullName: String,
@Email
@NotBlank(message = "email may not be blank")
var email: String,
@CreationTimestamp
var createdAt: LocalDateTime? = null,
@UpdateTimestamp
var updatedAt: LocalDateTime? = null,
)
为了完整起见,这是我的 UserRepository:
@ApplicationScoped
class UserRepository : PanacheRepository<User>
当我确定请求有效时,创建用户确实有效。但我也想确保无效请求在请求无效时得到很好的处理。这是当我点击 createUser 端点时我现在得到的响应:
com.fasterxml.jackson.databind.exc.ValueInstantiationException: Cannot construct instance of
`com.fortuneapp.backend.application.domain.core.models.entities.User`, problem: Parameter specified as non-null is null:
method com.fortuneapp.backend.application.domain.core.models.entities.User.<init>, parameter email
at [Source: (io.quarkus.vertx.http.runtime.VertxInputStream); line: 3, column: 1]
我在这里错过了什么?
您遇到了属性的可空性问题,正如您所看到的,即使您正在定义 var
属性,其中一些属性不可为空 ?
所以因为您正在反序列化一个 json 消息,其余服务的输入,Jackson 无法创建模型的新实例 class user
因为某些必填字段不存在。
这类似于您尝试创建新对象但未在构造函数中提供所需参数的情况。
这里有一些使用 kotlin、Jax-RS 和 Hibernate-Panache 的建议 https://quarkus.io/guides/kotlin。
您尝试归档的内容完全有可能,但如果您想将实体用作请求主体,则必须使所有字段都可为空,否则底层 Json 序列化程序将无法创建模型的新实例以通过 @Valid
验证并生成约束违规报告。
这里有一些选择。
- 您可以创建一个所有属性都可为空的数据 class,这样您就可以确保所有 javax 验证注释都能够被检查,因为请求将能够被反序列化。然后将此对象映射到您的模型实体 class。您可以将此 class 视为 DTO,因为最后您将通过层边界移动数据并将您的服务合同与您的实体模型实现解耦,这往往很方便。
- 尽管 javax.validation 约束注释的使用非常方便,但您可以注入验证器并检索约束违规和 return 具有约束违规的自定义数据 class以比默认报告更具可读性的方式,在 resteasy 的反应版本中,quarkus 不支持默认报告。
如果还有疑问我可以举个例子
将您的字段设置为可为空,初始化它们并将 @field:
放在注释之前,它将起作用。
@Entity
data class User (
@Id
@GeneratedValue(generator = "UUID")
var id: UUID? = UUID.randomUUID(),
@field:NotBlank
var fullName: String = null,
@field:Email
@NotBlank(message = "email may not be blank")
var email: String = null,
...