Skip to content
This repository has been archived by the owner on May 23, 2024. It is now read-only.

Check for additional properties in QNode/QEdge and respond with an error #571

Open
2 tasks
gaurav opened this issue Aug 25, 2022 · 0 comments
Open
2 tasks

Comments

@gaurav
Copy link
Member

gaurav commented Aug 25, 2022

Currently, CAM-KP-API decodes the TRAPIRequest in a non-strict manner: we do not throw an error if required properties are not included, if properties are incorrectly named, or if additional properties are added (as is allowed on several entities, including QNode and QEdge). While we can check for required properties by throwing an error if they are missing, incorrectly named properties are simply ignored; this is a violation of the TRAPI 1.3. specification, which requires that CAM-KP-API should generate a warning. The only way to report an error with these properties would be by adding a DecodeFailureHandler that can catch these errors and return the correct TRAPIResponse.

This is partially implemented in PR #560; however, there are two remaining issue to fix.

BiolinkPredicate/BiolinkClass currently require both shortname and iri fields to pass validation

BiolinkPredicate is defined in the domain/package.scala as:

final case class BiolinkPredicate(shorthand: String, iri: IRI) extends BiolinkTerm
object BiolinkPredicate {
implicit val embedInSPARQL = SPARQLInterpolator.embed[BiolinkPredicate](Case(SPARQLContext, SPARQLContext) { pred =>
val pss = new ParameterizedSparqlString()
pss.appendIri(pred.iri.value)
pss.toString
})
implicit object BiolinkPredicateFromQuerySolution extends FromQuerySolution[BiolinkPredicate] {
def fromQuerySolution(qs: QuerySolution, variablePath: String = ""): Try[BiolinkPredicate] =
getResource(qs, variablePath).map(r => BiolinkPredicate(r.getURI))
}
def apply(label: String): BiolinkPredicate =
if (!label.startsWith(BiolinkTerm.namespace)) {
BiolinkPredicate(label, IRI(s"${BiolinkTerm.namespace}$label"))
} else {
BiolinkPredicate(label.replace(BiolinkTerm.namespace, ""), IRI(s"$label"))
}
}
implicit class BiolinkPredicateOps(blPredicate: BiolinkPredicate) {
def withBiolinkPrefix = s"biolink:${blPredicate.shorthand}"
}

This allows us to define a BiolinkPredicate as either a single term (which is then separated into a shorthand and IRI) or as a shorthand/IRI pair. This allows a BiolinkPredicate to be defined in a TRAPIQuery as a single string, which is then converted internally into a BiolinkPredicate. Unfortunately, when strictDecoding is using, this causes validation to fail when the supplied BiolinkPredicate does not contain both shortname and iri properties, which isn't actually in the TRAPI specification.

There are several possible fixes; probably the simplest would be to specifically recognize these errors and -- if no other validation errors occur -- to silently discard them. But they do need to be fixed in some way.

The same issue also applies to BiolinkClass:

final case class BiolinkClass(shorthand: String, iri: IRI) extends BiolinkTerm
object BiolinkClass {
def apply(label: String): BiolinkClass =
if (label.contains("_")) {
BiolinkClass(label, IRI(s"${BiolinkTerm.namespace}${CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, label)}"))
} else {
BiolinkClass(label, IRI(s"${BiolinkTerm.namespace}${StringUtils.capitalize(label)}"))
}
implicit lazy val schema: Typeclass[BiolinkClass] = Schema.string
}
implicit class BiolinkClassOps(blClass: BiolinkClass) {
def withBiolinkPrefix = s"biolink:${blClass.shorthand}"
}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant