Fwd: [AS2.0] Activity and Actions Vocabulary, Examples

Further down this email you can find:

> A "PotentialAction" is an Activity that might occur in the future. I
> have modified the definition of this to be in closer alignment with
> the direction taken by schema.org/Actions without actually overlapping
> or introducing any dependencies on the schema.org Vocabulary. This
> ought to meant that the two models can peacefully coexist without
> giving developers two distinctly different ways of accomplishing the
> same thing. It's even possible to mix and match but I'll get into that
> later on.


-------- Original Message --------
Subject: Activity and Actions Vocabulary, Examples
Resent-Date: Tue, 30 Sep 2014 15:37:30 +0000
Resent-From: public-socialweb@w3.org
Date: Tue, 30 Sep 2014 08:36:39 -0700
From: James M Snell <jasnell@gmail.com>
To: public-socialweb@w3.org <public-socialweb@w3.org>,
public-social-interest@w3.org <public-social-interest@w3.org>

My apologies in advance, this is going to be a long note...

As a follow up to my note yesterday, I wanted to provide a few
examples that illustrate the changes that were made. These examples
are primarily going to focus on the use of JSON-LD, but I will also
show some examples using other serializations, including RDFa,
Microdata and a hypothetical Microformats mapping.

First, a few notes:

1. The "id" attribute is defined as an alias of JSON-LD's "@id", so in
the JSON-LD examples, I'm using the "@id"
2. "objectType" is defined as an alias of JSON-LD "@type", so the
examples will use "@type"
3. "language" is defined as an alias of JSON-LD "@language", so the
examples will use "@language"

To start this off, let's look first at a basic Activity might look
like prior to these changes. This *old* example makes use of several
bits that were controversial. I'm using this example so I can contrast
the changes that have been made.

Ex.A:

  {
    "id": "urn:example:activity:1",
    "actor": {
      "objectType": "person",
      "id": "urn:example:person:1",
      "displayName": "Sally Smith"
    },
    "verb": {
      "@id": "urn:example:verbs:edit",
      "displayName": "Edit"
    },
    "object": {
      "objectType": {
        "id": "urn:example:objectTypes:note",
        "displayName": "Note"
      },
      "content": "This is the content",
      "mediaType": "text/html",
      "url": "http://example.org/notes/1",
      "self": "http://api.example.org/notes/1.json",
      "icon": {
        "objectType": "urn:example:objectTypes:icon",
        "url": "http://example.org/assets/note.png"
      }
    }
  }

In this example, we see use of the Type Value and Link Value
constructs, the use of Link Relations as attribute names, and the use
of an Object value for "icon".

In the updated vocabulary model, the Type Value construct goes away,
Link Value's are redefined, and Link Relations are no longer mixed in
with the object property names. Also, the value of the "verb" property
is a Verb object, which (in JSON-LD) can be expressed as either a
simple IRI or a JSON object. In the new vocabulary model, this example
would be expressed as:

Ex.B:

  {
    "@id": "urn:example:activity:1",
    "actor": {
      "@type": "http://activitystrea.ms/1.0/person",
      "@id": "urn:example:person:1",
      "displayName": "Sally Smith"
    },
    "verb": {
      "@id": "urn:example:verbs:edit",
      "displayName": "Edit"
    },
    "object": {
      "@type": "urn:example:objectTypes:note",
      "content": "This is the content",
      "url": [
        {
          "@id": "http://example.org/notes/1",
          "mediaType": "text/html"
        }
        {
          "@id": "http://api.example.org/notes/1.json",
          "mediaType": "application/activity+json",
          "rel": "self"
        }
      ],
      "icon": "http://example.org/assets/note.png"
    }
  }

Note the structural changes on "url". In the Vocabulary, there is a
Link class. The Link class defines a link to some other resource.
Unlike in the previous version, Links are *not* Objects. Link's have a
target URL which is expressed as the Link instance's "@id". Links can
also have "rel" and "mediaType" attributes.

In the vocabulary, the "url", "icon" and "image" properties in
particular have been changed so that their values are strictly Links.
(Some of the other properties on Object and Activity can take either
Object or Link as their value). There are no cardinality restraints on
the "url", "icon" and "image" properties so any one object can have 1
or more values for each. Because of the way JSON-LD serialization
works, this means that we can express the value of these properties as
either: (a) a String with an IRI, (b) a Single json object with an
"@id", or (c) An array of IRIs/json objects. For instance, each of the
following are equivalent:

  "url": "http://example.org/foo"

  "url": { "@id": "http://example.org/foo" }

  "url": [ { "@id": "http://example.org/foo" } ]

In the previous model, all Link Value's had an associated Link
Relation. If the "rel" attribute did not appear in the Link Value
directly, the name of the property was used as the Link Relation. This
allowed us to use IANA and HTML5 link relations directly as property
names in our objects. While this qualified as a "neat trick" that was
convenient in some ways, many rightly pointed out that this mixing of
link relations and property names muddied the water a bit and opened
the door for naming conflicts. In the updated vocabulary this is
revised. The Link class has a "rel" attribute, and this attribute is
the only way to associate a Link Relation with the Link.

Given this snippet from Ex.B above:
      "url": [
        {
          "@id": "http://example.org/notes/1",
          "mediaType": "text/html"
        }
        {
          "@id": "http://api.example.org/notes/1.json",
          "mediaType": "application/activity+json",
          "rel": "self"
        }
      ]

The object has two "url" values. For the first value, the Link target
is "http://example.org/notes/1", the mediaType of that target is
"text/html" and there is no Link Relation. For the second, the Link
target is "http://api.example.org/notes/1.json", the mediaType is
"application/activity+json" and the Link Relation is "self".

If you look at the "icon" property for Ex.B, you'll see that there is
only a single Link provided. The Link target is
"http://example.org/assets/note.png" and no additional information is
given.

For "url", "icon" and "image", the value is *required* to be a Link.
However, for quite a few properties defined in the vocabulary, the
value can be either a Link or an Object. For instance, the "actor"
property on an Activity could have either of the following:

  "actor": {
    "@type": "urn:example:objectType:person",
    "displayName": "Sally"
  }

  "actor": {
    "@type": "http://activitystrea.ms/2.0/Link",
    "@id": "http://example.org/profiles/sally",
    "mediaType": "text.html"
  }

Or even a mix of the two:

  "actor": [
    {
      "@type": "urn:example:objectType:person",
      "displayName": "Sally"
    },
    {
      "@type": "http://activitystrea.ms/2.0/Link",
      "@id": "http://example.org/profiles/sally",
      "mediaType": "text.html"
    }
  ]

In such cases, it is important to explicitly specify the "@type" in
order to let a consuming application know what type of value is being
passed. Yes, that's a bit annoying, but it is what it is.
If the "@type" is omitted, then a reasonable default should be
assumed. I propose that the reasonable default is to assume that it's
an object.

As with Link, the JSON-LD serialization of the Object value is
flexible. If the Object consists of nothing else but an @id, then we
can serialize it simply as a String with an IRI. The following, then,
are equivalent:

  "actor": "urn:example:people:sally"

  "actor": {"@id": "urn:example:people:sally"}

  "actor": [{"@id": "urn:example:people:sally"}]

Note that while all this looks quite a bit different, because of the
way the vocabulary and JSON-LD context are defined, existing Activity
Streams 1.0 documents are still valid. For instance, if we look at
Ex.C below, which is taken from an existing Pump.io implementation:

Ex.C:

{
    "id": "http://coding.example/api/activity/bwkflwken",
    "actor": {
        "id": "acct:bwk@coding.example",
        "objectType": "person",
        "displayName": "Brian Kernighan"
    },
    "verb": "follow",
    "to": [{
        "id": "acct:ken@coding.example",
        "objectType": "person"
    }],
    "object": {
        "id": "acct:ken@coding.example",
        "objectType": "person",
        "displayName": "Ken Thompson"
    },
    "published": "1974-01-01T00:00:00",
    "links": [
        {"rel": "self", "href":
"http://coding.example/api/activity/bwkflwken"}
    ]
}

If we properly apply the JSON-LD @context when processing this, things
just work. The only wonkiness we get is with the "links" extension
property. A properly crafted JSON-LD @context can define "links" as an
alias of "url" and "href" as an alias of "@id". Once done, this
example is directly processable using the updated vocabulary without
requiring any changes to the original serialized document.

That covers the main changes to Object and Activity, let's look at
PotentialAction now.

A "PotentialAction" is an Activity that might occur in the future. I
have modified the definition of this to be in closer alignment with
the direction taken by schema.org/Actions without actually overlapping
or introducing any dependencies on the schema.org Vocabulary. This
ought to meant that the two models can peacefully coexist without
giving developers two distinctly different ways of accomplishing the
same thing. It's even possible to mix and match but I'll get into that
later on.

The model here is simple: Any Object can have one or more
PotentialAction's, expressed using the "action" property. A
PotentialAction can have one or more methods of completing that
action, expressed using the "using" property. For instance:

Ex.D:

  {
    "@type": "urn:example:objectTypes:note",
    "displayName": "My Note",
    "action": {
      "@type": "urn:example:action:LikeAction",
      "confirm": true,
      "using": {
        "@type": "http://activitystrea.ms/2.0/HttpRequest",
        "url": "http://api.example.org/like?id=1",
        "method": "POST",
        "potentialResult": {
          "@type": "http://activitystrea.ms/2.0/Payload",
          "mediaType": "application/activity+json"
        }
      }
    }
  }

Here we have a "urn:example:objectTypes:note" Object with a single
PotentialAction of type "urn:example:action:LikeAction". Invocation of
this action requires user confirmation (confirm: true). To invoke this
action, we would use an HTTP POST request to
"http://api.example.org/like?id=1" and would expect to get back a JSON
document.

Here's another example:

Ex.D:

  {
    "@type": "urn:example:objectTypes:movie",
    "displayName": "Vacation Video",
    "action": {
      "@type": "urn:example:action:ViewAction",
      "confirm": false,
      "using": {
        "@type": "http://activitystrea.ms/2.0/EmbeddedView",
        "url": {
          "@id": "http://example.org/movies/vacation.mpg",
          "mediaType": "video/mpeg"
        }
      }
    }
  }

Here we have a "urn:example:objectTypes:movie" object with a single
PotentialAction of type "urn:example:action:ViewAction". Invocation of
this action does *not* require user confirmation. To invoke the
action, we would use an Embedded View, which is really just the mpeg
file for the video itself.

The Vocabulary defines four specific types of "PotentialActionHandler"
instances:

 - HttpRequest (should be self explanatory)
 - BrowserView (a subclass of HttpRequest that results in the display
and navigation of a browser context)
 - EmbeddedView (displays embedded content)
 - Intent (largely undefined right now, the idea here is to shell out
to a native application or allow the consuming application to figure
out the details for itself...)

For folks who are familiar with the schema.org/Action way of doing
things (documented here: http://schema.org/docs/actions.html) much of
this ought to look pretty familiar. The differences between the two
models are *intentional*. The idea here is to follow the same basic
path without introducing any direct dependencies. There are also
additional use cases that simply are not covered by the current
schema.org/Actions model (embedded content, for instance). That said,
the two approaches are compatible with one another and can be used
together.

I can go into more detail on the PotentialActions bit later on. For
now, I'd like to turn attention back to other, non JSON-LD
serializations. With the vocabulary defined the way that it is, we can
easily serialize Activity and Action terms into HTML using either
HTML5's built in Microdata attributes, RDFa or Microformats. Here are
some examples:

Ex.E:

<div itemscope itemtype="http://activitystrea.ms/2.0/Activity"
itemid="urn:example:activity:1">
  <span itemprop="actor" itemscope
itemtype="urn:example:objectTypes:person">
    <span itemprop="displayName">Sally</span>
   </span>
  <span itemprop="verb" itemscope
itemtype="http://activitystrea.ms/2.0/Verb"
itemid="urn:example:verbs:upload">
    <span itemprop="displayName">uploaded</span>
  </span>
  <span itemprop="object" itemscope itemtype="urn:example:objectTypes:file">
    <span itemprop="displayName">a file</span>
    (<a href="http://example.org/foo.jpg" itemprop="url">...</a>)
  </span>
</div>

A bit verbose, yes, but that's the way HTML5 microdata works.

Using RDFa, it would look something like:

Ex.F:

  <div vocab="http://activitystrea.ms/2.0" typeof="Activity">
    <span property="actor" typeof="urn:example:objectTypes:person">
      <span property="displayName">Sally</span>
     </span>
    <span property="verb" typeof="http://activitystrea.ms/2.0/Verb"
resource="urn:example:verbs:upload">
      <span property="displayName">uploaded</span>
    </span>
    <span property="object" typeof="urn:example:objectTypes:file">
      <span property="displayName">a file</span>
      (<a href="http://example.org/foo.jpg" property="url">...</a>)
    </span>
  </div>

Using microformats we'd get something like (my microformats-foo is a
bit rusty so some details could likely be refined)

Ex.G:

   <div class="h-activity">
    <span class="p-actor">
      <span class="p-displayname">Sally</span>
     </span>
    <link class="p-verb" href="urn:example:verbs:upload">
      <span property="displayName">uploaded</span>
    </link>
    <span class="p-object">
      <link class="u-type" href="urn:example:objectTypes:file" />
      <a href="http://example.org/foo.jpg" class="u-url
p-displayName">a file</a>
    </span>
  </div>

We can even express the data using normalized N-Quads...

Ex.H:
  _:c14n0 <http://activitystrea.ms/2.0/displayName> "a file" .
  _:c14n0 <http://activitystrea.ms/2.0/url> <http://example.org/foo.jpg> .
  _:c14n0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
<urn:example:objectTypes:file> .
  _:c14n1 <http://activitystrea.ms/2.0/actor> <urn:example:people:sally> .
  _:c14n1 <http://activitystrea.ms/2.0/object> _:c14n0 .
  _:c14n1 <http://activitystrea.ms/2.0/verb> <urn:example:verbs:upload> .
  _:c14n1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
<http://activitystrea.ms/2.0/Activity> .

The bottom line is that, even if we specify JSON-LD as a baseline
serialization, defining the vocabulary in this way gives us quite a
few options we previously did not have with regards to serialization.

I'll stop here for now as I recognize that this is a lot of
information to process.

- James

Received on Friday, 3 October 2014 08:36:55 UTC