Activity Streams/Primer/Identifying Activity Objects
There are four main ways of identifying if an AS2 object is an Activity
.
- By its location in the world. For example, ActivityPub inbox and outbox streams contain only Activity objects.
- Check its
type
agains a list of known activity types from the vocabulary spec. - As a heuristic, it's possible to ducktype an Activity by looking for properties of an Activity like
actor
,object
,target
,result
,origin
, orinstrument
. - 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.