eclipsesource/play-json-schema-validator

Question: Ref resolution outside of validation?

Closed this issue · 2 comments

By introducing this library into our code, we have been able to leverage additional JSON schema features, such as $ref resolution, for JSON validation.

Beyond validation, we are parsing valid JSON payloads into our own domain types using JSON schemas.

For illustration, we have something like this:

trait Value
case class BooleanValue private(value: Boolean) extends Value
case class StringValue private(value: String) extends Value
case class IntegerValue private(value: BigInt) extends Value
case class NumberValue private(value: BigDecimal) extends Value
case class DateTimeValue private(value: OffsetDateTime) extends Value

object Value {
  def fromBoolean(value: Boolean): Value = BooleanValue(value)
  def fromInteger(value: BigInt): Value = IntegerValue(value)
  def fromNumber(value: BigDecimal): Value = NumberValue(value)
  def fromString(value: String, format: Option[String]): Value = format match {
    case Some(f) if f == "date-time" =>
      DateTimeValue(OffsetDateTime.parse(value, DateTimeFormatter.ISO_OFFSET_DATE_TIME))
    case _ =>
      StringValue(value)
  }
}

case class Element(path: JsPath, value: Value)

def validatedElements(
  schema: SchemaType,
  json: JsValue
): Either[Seq[(JsPath, Seq[ValidationError])], List[Element]] = ???

validatedElements here recursively walks the schema and flattens the JSON payload into a list of JsPath-Value pairs using the corresponding SchemaType for each leaf of the JSON payload.

Given a schema such as

{
  "type": "object",
  "properties": {
    "organization": {
      "allOf": [
        { "$ref": "#/definitions/organization" }
      ]
    }
  },
  "definitions": {
    "organization": {
      "type": "object",
      "properties": {
        "createdAt": { "type": "string", "format": "date-time" }
      },
      "required": ["createdAt"],
      "additionalProperties": false
    }
  }
}

we would like to parse a valid payload into

List(
  Element(JsPath("/organization/createdAt"), aDateTimeValue)
)

We are able to validate the incoming JSON payload with a SchemaValidator(). However, we have not been able to use the same schema to parse the JSON payload, correctly handling ref resolution. As far as I can tell, all ref resolution / ref caching is package-private.

My question is:

(a) is there a way to achieve this already?
(b) if not, would it be within the scope of this library to open up ref resolution for traversing JSON schemas outside of validation? If so, I'd be happy to crack at it.

(a) No, unfortunately not. All there is are the overloads of the validate methods of the SchemaValidator which allow you to pass in additional Reads[A] that utilize Play JSON Reads to convert a JsValue into A. This was enough for our initial needs to retrieve a domain type from a JsValue, but I don't think it fits your needs.
(b) Yes, I think it is definitely in the scope of the library to provide a generic way to traverse a JSON schema (perhaps, validation then also might become an instance of traversing the schema). So, yes, please go ahead. I currently don't have much time but if I can be of any help, let me know. If you find any issues or have any questions, you can of course also drop me a mail.

Sounds good—thanks @edgarmueller