
com.rmn.jsonapi.models.Resource.scala Maven / Gradle / Ivy
The newest version!
package com.rmn.jsonapi.models
import com.rmn.jsonapi.formatters.TypeFormatter
import com.rmn.jsonapi.types.{MetaTypes, AttributeTypes, ResourceLinkTypes, RelationshipTypes}
import play.api.libs.functional.syntax._
import play.api.libs.json._
case class Resource[Attr: AttributeTypes, Rels: RelationshipTypes, Links: ResourceLinkTypes, Meta: MetaTypes](
`type`: String,
id: String,
attributes: Attr,
relationships: Rels,
links: Links,
meta: Meta
)
object AdhocValidate {
def apply(validate: JsValue => Iterable[JsError]): Reads[JsValue] = {
Reads[JsValue] { json =>
val errs = validate(json)
if (errs.isEmpty) {
JsSuccess(json)
} else {
errs.reduce(_ ++ _)
}
}
}
}
object Resource {
implicit def formats[Attr: AttributeTypes, Rels: RelationshipTypes, Links: ResourceLinkTypes, Meta: MetaTypes]: Format[Resource[Attr, Rels, Links, Meta]] = {
val reserved = Set("")
// http://jsonapi.org/format/#document-resource-object-fields
def checkFields(attr: JsObject, rels: JsObject): Iterable[JsError] = {
val counts = (Seq("id", "type") ++ attr.keys.toSeq ++ rels.keys.toSeq).groupBy(identity).mapValues(_.size)
counts.filter { case (field, count) => count > 1 }.map { case (field, count) => JsError(s"error.jsonapi.field.duplicate('$field')") }
}
// http://jsonapi.org/format/#document-resource-object-attributes
def checkReserved(attr: JsObject) : Iterable[JsError] = {
val rels = if ((attr \\ "relationships").nonEmpty) {
Seq(JsError(s"error.jsonapi.attributes.reserved-member('relationships')"))
} else {
Seq[JsError]()
}
val links = if ((attr \\ "links").nonEmpty) {
Seq(JsError(s"error.jsonapi.attributes.reserved-member('links')"))
} else {
Seq[JsError]()
}
rels ++ links
}
Format[Resource[Attr, Rels, Links, Meta]](
(
AdhocValidate { json =>
val root = json.asOpt[JsObject].getOrElse(Json.obj())
val attrs = root.value.get("attributes").flatMap(_.asOpt[JsObject]).getOrElse(Json.obj())
val rels = root.value.get("relationships").flatMap(_.asOpt[JsObject]).getOrElse(Json.obj())
checkFields(attrs, rels) ++ checkReserved(attrs)
} andKeep
(__ \ "type").read[String] and
(__ \ "id").read[String] and
implicitly[TypeFormatter[Attr]].readAt(__ \ "attributes") and
implicitly[TypeFormatter[Rels]].readAt(__ \ "relationships") and
implicitly[TypeFormatter[Links]].readAt(__ \ "links") and
implicitly[TypeFormatter[Meta]].readAt(__ \ "meta")
) (Resource.apply[Attr, Rels, Links, Meta] _),
(
(__ \ "type").write[String] and
(__ \ "id").write[String] and
implicitly[TypeFormatter[Attr]].writeAt(__ \ "attributes") and
implicitly[TypeFormatter[Rels]].writeAt(__ \ "relationships") and
implicitly[TypeFormatter[Links]].writeAt(__ \ "links") and
implicitly[TypeFormatter[Meta]].writeAt(__ \ "meta")
) (unlift(Resource.unapply[Attr, Rels, Links, Meta]))
)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy