Activity Streams/Primer/Identifying Activity Objects

From W3C Wiki

There are four main ways of identifying if an AS2 object is an Activity.

  1. By its location in the world. For example, ActivityPub inbox and outbox streams contain only Activity objects.
  2. Check its type agains a list of known activity types from the vocabulary spec.
  3. As a heuristic, it's possible to ducktype an Activity by looking for properties of an Activity like actor, object, target, result, origin, or instrument.
  4. Using inference against an RDF schema or OWL ontology. This only works if the extension also provides an RDF schema or OWL ontology, or if one can be generated from a canonical specification document. It should be possible to determine that a given type is a direct or indirect sub-type of Activity if the schema, ontology, or specification declares that the class in question is an RDF Schema "subclass of" (https://www.w3.org/2000/01/rdf-schema#subClassOf) the Activity class (https://www.w3.org/ns/activitystreams#Activity), or possibly needing to recurse through the hierarchy of classes).

Examples

By location

Consider this Activity object:

{
   "@context": "https://w3.org/ns/activitystreams",
   "type": "Person",
   "name": "The Chef",
   "outbox": {
      "type": "OrderedCollection",
      "items": [
        {
          "type": "Bake",
          "summary": "The Chef baked a chocolate cake.",
          "object": {
               "type": "Cake",
               "name": "Chocolate Cake"
          }
        }
      ]
   }
}

It represents a Person with an ActivityPub outbox property. Because the outbox contains Activity objects, we know that the first object in the items array is an Activity, specifically a Bake activity.

By type

Consider an extension vocabulary to Activity Streams for baking. Here's an Activity for baking a cake:

{
    "@context": [
        "https://w3.org/ns/activitystreams",
        {
            "kitchen": "https://kitchen.example/",
            "Bake": {
                "@id": "kitchen:Bake",
                "@type": "@id",
            },
            "Cake": {
                "@id": "kitchen:Cake",
                "@type": "@id",
            }
        }
    ],
    "type": ["Bake", "Create"],
    "actor": "https://kitchen.example/chef",
    "summary": "The Chef baked a chocolate cake.",
    "object": {
        "type": "Cake",
        "name": "Chocolate Cake"
    }
}

The producer of this activity has included multiple types. We can find "Create" in the list of Activity object types from the vocabulary doc, so we know it's an Activity object.

By property

Here's a similar example with a single type:

{
    "@context": [
        "https://w3.org/ns/activitystreams",
        {
            "kitchen": "https://kitchen.example/",
            "Bake": {
                "@id": "kitchen:Bake",
                "@type": "@id",
            },
            "Cake": {
                "@id": "kitchen:Cake",
                "@type": "@id",
            }
        }
    ],
    "type": "Bake",
    "actor": "https://kitchen.example/chef",
    "summary": "The Chef baked a chocolate cake.",
    "object": {
        "type": "Cake",
        "name": "Chocolate Cake"
    }
}

The consumer can infer that this is an Activity because it has the "actor" and "object" properties.

By inferencing

Suppose that the extension vocabulary provides the following excerpted schema or ontology:

@prefix kitchen: <https://kitchen.example/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix as: <https://www.w3.org/ns/activitystreams#> .

kitchen:Bake a rdf:Class;
  rdfs:subClassOf as:Activity .

By importing these statements into an inferencing program, we can know definitively that Bake is a type of Activity, because it is explicitly defined as such.