CredentialEngine / CredentialRegistry

Repository for development of the Credential Registry
Apache License 2.0
12 stars 10 forks source link

Inject graph bnodes into resource documents #694

Closed siuc-nate closed 4 months ago

siuc-nate commented 5 months ago

Whenever we have a JSON-LD @graph with one or more bnodes, and the user requests a resource (via the /resources/ URI) which references any of those bnodes, we need to be able to include those bnodes with the resource in an array that gets dynamically injected to the resource document in much the same way we currently inject the JSON-LD @context link.

The existing functionality already handles /graph/ requests just fine, but we need to update the handling for /resources/ requests to avoid broken links to bnodes. In the examples below, the "Main" and "Secondary" resources are all top-level objects with CTIDs and their own /resources/ URI (e.g. a competency framework and its competencies, a rubric and its criteria, a pathway and its components, etc) which share a graph with some number of bnodes: image

Fortunately, the JSON-LD specification provides a way of doing this that is RDF-friendly via a property called @included. I suggest we look it over closely and, if there are no problems, implement it.

This would have the following effects:

Determining "relevant" bnodes would entail crawling all outbound bnode connections from the resource that was requested, including those bnodes, and recursively crawling those bnodes for any other bnodes that they reference, and crawling those bnodes, and so on.

Only outbound references that point directly to bnodes would be considered for performance and practicality reasons. image

If we determine that this recursive crawling is too detrimental to performance, plan B would be to just always include all bnodes from the resource's JSON-LD @graph (perhaps with some basic scan for bnode URIs so that we aren't including them for resources that don't reference any bnodes) image

Example (it doesn't really matter where @included gets injected, maybe just always put it at the end for readability):

User requests "https://credentialengineregistry.org/graph/ce-abc...". The data is returned as it is today (the same way it was published):

{
  "@context": "https://...",
  "@id": "https://credentialengineregistry.org/graph/ce-abc...",
  "@graph": [
    {
      "@id": "https://credentialengineregistry.org/resources/ce-abc...",
      "@type": "ceterms:Certificate",
      "ceterms:name": { "en": "Some accredited credential" },
      "ceterms:accreditedBy": [ "_:123abcetcetc" ]
    },
    {
      "@id": "_:123abcetcetc",
      "@type": "ceterms:QACredentialOrganization",
      "ceterms:name": { "en": "Some accrediting body that isn't published and only has a bnode" }
    }
  ]
}

User requests "https://credentialengineregistry.org/resources/ce-abc...". The QA Credential Organization gets included via @included:

{
  "@context": "https://...",
  "@id": "https://credentialengineregistry.org/resources/ce-abc...",
  "@type": "ceterms:Certificate",
  "ceterms:name": { "en": "Some accredited credential" },
  "ceterms:accreditedBy": [ "_:123abcetcetc" ],
  "@included": [
    {
      "@id": "_:123abcetcetc",
      "@type": "ceterms:QACredentialOrganization",
      "ceterms:name": { "en": "Some accrediting body that isn't published and only has a bnode" }
    }
  ]
}
philbarker commented 5 months ago

Good summary. Watch out for cyclical chains when recursing through BNodes! e.g. _:A :related _:B. _:B :related _:C. _:C :related _:A.

siuc-nate commented 4 months ago

This is now working.