[Resolved] Trying to understand "Follow" activity structure

Hi,

Brand new to ActivityPub, experimenting with implementing the s2s part of the protocol.

I am a bit confused by the “Follow” example in the ActivityStreams vocabulary: Activity Vocabulary

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "summary": "Sally followed John",
  "type": "Follow",
  "actor": {
    "type": "Person",
    "name": "Sally"
  },
  "object": {
    "type": "Person",
    "name": "John"
  }
}

From what I understand based on this description in the spec, the above would be sent to an actor’s Inbox, correct? If so, what is the purpose of the “object” property in the activity? I would expect the actor to be deduced by the inbox URI that the activity was POSTed to.

My next question is about the “actor” (presumably the actor following the object): I’m not quite sure what the “name” is for in this example and why it is not an ID. How is the receiving server meant to know what external server the following actor is being hosted on and what their exact ID is (I don’t think the name has any uniqueness guarantees)?

What am I missing? Thanks in advance for any input.

3 Likes

Follow Activities arent always POSTed to the actor’s inbox. Sometimes it can be posted to Share Inboxes well. So can’t always be deduced by the inbox URI. See

Thanks; I understand that they are POSTed to the inbox (but great to have confirmation). My question is more about the contents of the activity itself as shown in the ActivtyStream vocab example I linked. I was specifically confused about the “name” field, and the lack of “ID” field in said example.

Actually, looking at this Mastodon tutorial, it seems like the Follow activity doesn’t actually have to contain the properties in the given example…

{
	"@context": "https://www.w3.org/ns/activitystreams",
	"id": "https://my-example.com/my-first-follow",
	"type": "Follow",
	"actor": "https://my-example.com/actor",
	"object": "https://mastodon.social/users/Mastodon"
}

I am mostly confused/a little concerned about compliance across implementations here. If the ActivityStream doc example says we need an object with a type and a name and the Mastodon example only provides a string with the actor ID, how do ActivityPub implementations guarantee support across implementations? Is mandating support for either a single ID string or an object with the aforementioned properties specified in the spec somewhere that I missed?

Hi, I think the base level confusion here is in two parts. One, the ActivityStreams Vocabulary spec is designed to be a generic vocabulary that any spec can use, it’s not specific to ActivityPub and wasn’t necessarily designed with ActivityPub in mind. So the examples in the ActivityStreams spec may not be tuned to the specific requirements of ActivityPub, like requiring that every document has an id property.

Two, JSON-LD documents consider a nested object and a string referencing the id of that object to be identical. So the following two documents are identical from an ActivityPub perspective:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "https://my-example.com/my-first-follow",
  "type": "Follow",
  "actor": "https://my-example.com/actor",
  "object": "https://mastodon.social/users/Mastodon"
}

and

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "https://my-example.com/my-first-follow",
  "type": "Follow",
  "actor": "https://my-example.com/actor",
  "object": {
    "id": "https://mastodon.social/users/Mastodon",
    "type": "Person",
    "preferredUsername": "Mastodon",
    "name": "The official Mastodon account"
    // ...etc
  }
}

I hope this resolves some of your confusion. I’ve gone into more detail below:

Yes.

https://www.w3.org/TR/activitystreams-core/#jsonld
The serialized JSON form of an Activity Streams 2.0 document must be consistent with what would be produced by the standard JSON-LD 1.0 Processing Algorithms and API [JSON-LD-API] Compaction Algorithm using, at least, the normative JSON-LD @context definition provided here.

The spec doesn’t spell out all of the consequences of this, but the most important one is noted briefly (in a section about dealing with deprecated ActivityStreams 1.0 syntax): “The JSON-LD serialization allows such property values to be expressed as either an IRI String, an JSON object, or an Array of IRI Strings and JSON objects”.

All properties that have a range of @id can be given as a bare URI or a nested object, with no distinction made between the two.

The properties in the activity come from the ActivityStreams spec, which is separate from ActivityPub, so it needs to make sense as a standalone object, not just as a “payload” for ActivityPub transmission. So even though object (the “target” of the Activity) might be duplicative with information available in some contexts, the Activity Streams spec examples don’t Also, as @mk3 mentioned, while most of the time the activity is posted to a user’s inbox, that’s not the only context it might appear in—a Client to Server implementation might post a Follow activity to their outbox, servers might optimize by sending the Follow activity to the global sharedInbox instead of an actor’s specific inbox, activities might be stored for later retrieval or referenced somewhere else (such as an Undo), so it’s just better to think of the Follow document as self-contained.

name is a property on all Object. You can view its definition here: https://www.w3.org/TR/activitystreams-vocabulary/#dfn-name

A simple, human-readable, plain-text name for the object. HTML markup must not be included. The name may be expressed using multiple language-tagged values.

It is not an id because it represents the actors name, not their ID.

What you’re looking at here is an ActivityStreams document, which is not suitable for ActivityPub processing on its own. See section 3.1 of the ActivityPub spec:

All Objects in [ActivityStreams] should have unique global identifiers. ActivityPub extends this requirement; all objects distributed by the ActivityPub protocol MUST have unique global identifiers, unless they are intentionally transient (short lived activities that are not intended to be able to be looked up, such as some kinds of chat messages or game notifications).

The example of an ActivityStreams Follow activity would not be suitable for ActivityPub processing on its own, without at least an id property (which would allow the rest of the properties to be fetched).

4 Likes

Thank you, this cleared up all of my questions. I had mistakenly thought ActivityStreams and ActivityPub were more tightly coupled than they actually are. I think everything makes sense now, I appreciate the super thorough breakdown and all of the references.

1 Like

Great! I’m glad it was helpful. Let me know if you have any other questions.

1 Like