Akka HTTP의 검증 라이브러리를 만들었습니다.
도전
라는 것이있었습니다. Play라고 Form에 밸리데이션의 API가 있습니다만, Akka HTTP로는 없을 것 같아&조사해도 3rd party 라이브러리로서도 별로 없을 것 같다.
그래서 시험에 스스로 만들어 보았습니다.
만든 것
유효성 검사를 위반하는 요청을 보내면 이러한 응답이 반환됩니다.
중첩된 객체나 Array에도 대응하고 있습니다.
응답의 details에게는, 보내진 json의 「어떤 Key가 어떤 이유로 안되는지」를 각각 돌려줍니다.
만들 때 생각한 것
API 사양
Play의 Validation이면 반환 값이
{
"obj1.obj2.column1[0]": "error.required"
}
와 같은 형태로 돌아오므로, 에러 내용을 화면에서 취급하려면 Key의 문자열을 퍼스 하지 않으면 안 되고 사용하기 어려웠으므로, 이번은 이런 형태로 돌려주고 싶었다.
{
"obj1": {
"obj2": {
"column1": {
"0": "error.required"
}
}
}
}
코드 해설
크기로서는 100행도 없는 작은 라이브러리입니다.
Validation 정의
JSON은
Object
, Array
가 중첩되어 마지막으로 리터럴 값이 나옵니다.그들을 다루기 위해,
trait ValidatorBase[T] {
def validate(model: T): Option[JsValue]
}
trait ValidatorSeq[T] extends ValidatorBase[Seq[T]]
trait Validator[T] extends ValidatorBase[T]
각각을 정의합니다.
그리고, 각각에서 재귀적으로 validate 메소드를 호출하는 것으로 밸리데이션 결과가 조립되어 최종적으로는 하나의
Option[JsValue]
형태가 생성되어 그것을 응답에 건네주는 형태가 됩니다.실제로 사용자 코드에서 유효성 검사를 정의할 때,
- 어떤 키의 유효성 검사
- 어떤 밸리데이션을 걸까
- 실패한 경우 어떤 메시지를 발행할지
같은 내용을 전달하여 정의합니다.
case class Tag(
id: Int,
text: String
)
object TagValidator extends Validator[Tag] {
private def idRule: Validation =
genValidation(
"id",
tag => tag.id <= 0,
"id must be positive"
)
private def textRule: Validation =
genValidation(
"text",
tag => tag.text.isEmpty,
"text must not be empty"
)
val validations = Seq(idRule, textRule)
}
또한 중첩 된 객체에 대한 유효성 검사를 원하면 중첩 된 객체에 대해 이미 만든 Validator를 전달하여 대응합니다.
private def tagRule: Validation =
genValidationInternal(
"tag",
nested => nested.tag,
TagValidator
)
Validation 호출
Akka HTTP의 JSON Support와 함께하는 일은 동일하며,
- 자작 클래스의 변환(밸리데이션)을 정의해, 호출측에서 extends 한다
- 변환(밸리데이션)의 API를 호출할 때, implicit parameter로서 상기에서 만든 정의를 건네준다.
라는 형태입니다.
htps // c c. 어? 이오/도 cs/아카-h tp/콰렌 t/코몬/j そーすっぽ rt. HTML
trait CustomValidationDirectives extends ValidationDirectiveBase {
implicit val tagV = TagValidator
implicit val taglistV = TagListValidator
implicit val nestedTagV = NestedTagValidator
}
object Main extends CustomValidationDirectives with CustomJsonFormat {
validate(as[Tag]) { tag => // JSON to validated Tag
...
}
ValidationDirectiveBase
를 extends한 자바 커스텀 지시어를 만듭니다.호출측에서는, 그것을 상속하는 것으로,
validate
지시어와, implicit에 Validator를 건네주는 as[T]
를 사용할 수 있게 됩니다.여기서
as[T]
는 akka-http-spray-json의 as[T]
가 아닙니다.// akka-http-spray-json
def as[T](implicit um: FromRequestUnmarshaller[T]) = um
// akka-http-json-validation
def as[T](implicit um: FromRequestUnmarshaller[T], validator: ValidatorBase[T]): (FromRequestUnmarshaller[T], ValidatorBase[T]) = (um, validator)
validate
지시문에서는, 이 「JSON 로부터 Entity 로의 변환 정의」, 「Entity 의 밸리데이션 정의」를 사용하는 것으로, validate 끝난 데이터를 돌려줍니다.요약
구현을 통해 Akka HTTP에서 사용자 지정 지시문을 사용하는 방법과 implicit에 주입되는 것의 동작을 확인했습니다.
짧은 코드이므로, 꼭 읽어 주셔서 코멘트하실 수 있으면 기쁩니다.
Reference
이 문제에 관하여(Akka HTTP의 검증 라이브러리를 만들었습니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/uryyyyyyy/items/83f5a0931f89d8c2e78e텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)