Issues will not be fixed and new features will not be implemented unless PRs are submitted. The former maintainer no longer has the time and resources to work on this project further.
If you're interested in taking over, please reply to #146.
This is a JSON schema (draft v4/draft v7) validation library for Scala based on Play's JSON library.
If you experience any issues or have feature requests etc., please don't hesitate to file an issue. Thanks!
Add an additional resolver to your build.sbt
file:
resolvers += "emueller-bintray" at "http://dl.bintray.com/emueller/maven"
Then add the dependency (supporting Scala 2.12/2.13):
libraryDependencies += "com.eclipsesource" %% "play-json-schema-validator" % "0.9.5"
Please also see the respective release notes.
Schemas can be parsed by passing the schema string to Json.fromJson
. Starting with 0.9.5 (which adds draft 7 support), Reads
and Writes
have become version specific, hence you need to import them via respective Version object:
import Version7._ // since 0.9.5 necessary
val schema = Json.fromJson[SchemaType](Json.parse(
"""{
|"properties": {
| "$id": { "type": "integer" },
| "title": { "type": "string" },
| "body": { "type": "string" }
|}
}""".stripMargin)).get
With a schema at hand, we can now validate JsValue
s via the SchemaValidator
:
val validator = SchemaValidator(Some(Version7))
validator.validate(schema, json)
validate
returns a JsResult[A]
. JsResult
can either be a JsSuccess
or a JsError
.
validate
is also provided with overloaded alternatives where Play's Reads
or Writes
instances can be passed additionally.
This is useful for mapping JsValue
s onto case classes and vice versa:
validate[A](schemaUrl: URL, input: => JsValue, reads: Reads[A]) : JsResult[A]
validate[A](schemaUrl: URL, input: A, writes: Writes[A]): JsResult[JsValue]
validate[A: Format](schemaUrl: URL, input: A): JsResult[A]
In case the validate
method returns an failure, errors can be converted to JSON by calling the toJson
method.
Below is given an example taken from the example app:
import com.eclipsesource.schema._ // brings toJson into scope
val result = validator.validate(schema, json, Post.reads)
result.fold(
invalid = { errors => BadRequest(errors.toJson) },
valid = { post => ... }
)
Errors feature a schemaPath
, an instancePath
, a value
and a msgs
property. While schemaPath
and instancePath
should be self explanatory, value
holds the validated value and msgs
holds all errors related to the validated value. The value of the msgs
property is always an array. Below is an example, again taken from the example app.
{
"schemaPath" : "#/properties/title",
"keyword": "minLength",
"instancePath" : "/title",
"value" : "a",
"msgs" : [ "a violates min length of 3", "a does not match pattern ^[A-Z].*" ],
"errors": []
}
The value of schemaPath
will be updated when following any refs, hence when validating
{
"properties": {
"foo": {"type": "integer"},
"bar": {"$ref": "#/properties/foo"}
}
}
the generated error report's schemaPath
property will point to #/properties/foo
.
In case the schema to validate against makes use of the id
property to alter resolution scope (or if the schema has been loaded via an URL
), the error report also contains a resolutionScope
property.
In case of allOf
, anyOf
and oneOf
, the errors
array property holds the actual sub errors. For instance, if we have a schema like the following:
{
"anyOf": [
{ "type": "integer" },
{ "minimum": 2 }
]
}
and we validate the value 1.5
, the toJson
method returns this error:
[ {
"schemaPath" : "#",
"errors" : {
"/anyOf/0" : [ {
"schemaPath" : "#/anyOf/0",
"errors" : { },
"msgs" : [ "Wrong type. Expected integer, was number" ],
"value" : 1.5,
"instancePath" : "/"
} ],
"/anyOf/1" : [ {
"schemaPath" : "#/anyOf/1",
"errors" : { },
"msgs" : [ "minimum violated: 1.5 is less than 2" ],
"value" : 1.5,
"instancePath" : "/"
} ]
},
"msgs" : [ "Instance does not match any of the schemas" ],
"value" : 1.5,
"instancePath" : "/"
} ]
The validator allows you to alter error messages via scala-i18n,
e.g. for localizing errors reports.
You can alter messages by placing a messages_XX.txt
into your resources folder (by default conf
).
The keys used for replacing messages can be found here.
In case you use the validator within a Play application, you'll need to convert Play's Lang
and make it implicitly available for the SchemaValidator
, e.g. via:
implicit def fromPlayLang(lang: Lang): com.osinka.i18n.Lang = com.osinka.i18n.Lang(lang.locale)
An online demo of the library can be found here.
See the respective github repo for the source code.