w3c / json-ld-syntax

JSON-LD 1.1 Specification
https://w3c.github.io/json-ld-syntax/
Other
112 stars 22 forks source link

advice on what to do when encountering @protected terms (vcdm/as2) #424

Closed gobengo closed 7 months ago

gobengo commented 9 months ago

Take this example JSON-LD. it appears to be erroneous do to the mediaType property being protected in the outer context, and trying to be redefined in the inner context

The outer context from "https://www.w3.org/ns/credentials/v2" defines a mediaType term as @protected and with a different IRI as the context inside the credentialSubject which is ActivityStreams2.

If possible, I'd love for the JSON serialization of the credentialSubject.icon.mediaType to map to https://www.w3.org/ns/activitystreams#mediaType but still use the JSON key mediaType.

This is the first time I've encountered @protected terms, so I'm trying to grok what my options are.

After tinkering around a bit, I think it might not be possible to do what I want. (so, for now, when I try to make this JSON-LD, I compact the credentialSubject with a context like { "as": "https://www.w3.org/ns/activitystreams#" }, but then of course I lose credentialSubject.icon.mediaType and get credentialSubject.icon["as:mediaType"].

I also tried to insert a null in the credentialSubject["@context"] array, but I think that isn't allowed at least by jsonld.js (which I assume is pretty faithful to the spec).

{
  "type": [
    "VerifiableCredential"
  ],
  "credentialSubject": {
    "@context": [
      "https://www.w3.org/ns/activitystreams"
    ],
    "type": [
      "Organization"
    ],
    "icon": {
      "type": "Link",
      "mediaType": "image/png"
    }
  },
  "@context": [
    "https://www.w3.org/ns/credentials/v2"
  ]
}
Fak3 commented 9 months ago

Related to #361

dlongley commented 9 months ago

Here is an option that is based off of Example 2 from the Activity Streams spec, which looks like this:

{
  "@context": {
     "@vocab": "https://www.w3.org/ns/activitystreams",
     "ext": "https://canine-extension.example/terms/",
     "@language": "en"
  },
  "summary": "A note",
  "type": "Note",
  "content": "My dog has fleas.",
  "ext:nose": 0,
  "ext:smell": "terrible"
}

You can do this:

{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    {
      "@vocab": "https://www.w3.org/ns/activitystreams#",
      "icon": {
        "@id": "https://www.w3.org/ns/activitystreams#icon",
        "@type": "@id",
        "@context": {
          "mediaType": "https://www.w3.org/ns/activitystreams#mediaType"
        }
      }
    }
  ],
  "type": [
    "VerifiableCredential"
  ],
  "credentialSubject": {
    "type": [
      "Organization"
    ],
    "icon": {
      "type": "Link",
      "mediaType": "image/png"
    }
  }
}

Playground link: http://tinyurl.com/yvhnf7vr

Note that protected terms can only be overridden when a new term definition is provided with a scoped context -- such that the terms being overridden will be scoped to that new term only. This ensures that consumers can have confidence in the definitions being used based on the structure of the JSON tree.

If you wanted to bring in the entire AS context you could also do so using @import, but there's currently a bug with the playground that disallows it because it thinks that the @vocab keyword itself (from the AS context) is being redefined (and you can't ever redefine keywords). Once fixed this should also work:

{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    {
      "@import": "https://www.w3.org/ns/activitystreams",
      "mediaType": {
        "@id": "https://schema.org/encodingFormat"
      },
      "icon": {
        "@id": "https://www.w3.org/ns/activitystreams#icon",
        "@type": "@id",
        "@context": {
          "mediaType": "https://www.w3.org/ns/activitystreams#mediaType"
        }
      }
    }
  ],
  "type": [
    "VerifiableCredential"
  ],
  "credentialSubject": {
    "type": [
      "Organization"
    ],
    "icon": {
      "type": "Link",
      "mediaType": "image/png"
    }
  }
}

http://tinyurl.com/33fyyeuf

This approach does an "inline edit" of the AS v2 context via the @import feature to fix up the offending definition (mediaType) and adds the AS alternative definition for it when it is nested within icon.

So there should be a few options here to cause the output to behave properly. Ideally, I think, someone would construct a more modern activity streams context that uses scoped contexts to isolate definitions for usage with other documents types such as VCs. Alternatively, @vocab could be relied on as in the first working example here.

gobengo commented 9 months ago

@dlongley Thank you, Dave. This looks extremely helpful. I did see in spec text that there may be an affordance for this, but couldn't figure it out in the playground. Sounds like maybe I didn't do the right incantation. Will try it out and get back to you here. tysm!

davidlehn commented 7 months ago

Another possible path is to define a property with a scoped context and use that in credentialSubject. Shown here with an inline context, but this could be put in a small https://www.w3.org/ns/activitystreams-vc context if the only use of AS properties is under the special property. I think the output n-quads are what one would expect. There may be some variations of this.

{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    {
      "BIKESHED": {
        "@id": "https://www.w3.org/ns/activitystreams#credential",
        "@type": "@id",
        "@context": "https://www.w3.org/ns/activitystreams"
      }
    }
  ],
  "type": [
    "VerifiableCredential"
  ],
  "credentialSubject": {
    "BIKESHED": {
      "type": [
        "Organization"
      ],
      "name": "imaorg",
      "icon": {
        "type": "Link",
        "mediaType": "image/png"
      }
    }
  }
}

https://tinyurl.com/253tu643

Pros:

Cons:

gobengo commented 7 months ago

I have the advice I was originally looking for now. tysm all