ActivityPods specificity

In this document, you can find descriptions for ActivityPods-specific APIs and protocol workflows. In the future, we will be contributing to related working groups, to bring the following specifications into official drafts.

SPARQL endpoint

Every Pod comes with an SPARQL endpoint, linked to the WebID with the void:sparqlEndpoint predicate. Only SPARQL queries are supported, not SPARQL updates (You MUST use LDP or ActivityPub to modify data). WAC permissions are applied to all SPARQL queries, in order to return only the resources that the autenticated user or application has the right to see.

Authentication

Proxy endpoint with non-GET methods

We have extended the ActivityPub proxy endpoint to support HTTP methods others than GET.

To do that, you may pass a `multipart/form-data“ Content-Type with the following fields:

  • id: The URI of the resource
  • method: The HTTP method to use (default to GET)
  • headers: The HTTP headers to pass to the request (in JSON format)
  • body: The body of the request (optional)

Capability URL

We implement capability resources which are defined as WAC Authorizations:

{
  "@context": { "acl": "http://www.w3.org/ns/auth/acl#" },
  "@id": "https://myserver.com/capabilities/k3kleict5ks3r4",
  "@type": "acl:Authorization",
  "acl:accessTo": "https://myserver.com/resource/x",
  "acl:mode": "acl:Write"
}

Anyone who know the capability URL can access its corresponding resource like this:

GET /capabilities/k3kleict5ks3r4 HTTP/1.1
Host: myserver.com
Accept: application/ld+json
Authorization: Capability https://myserver.com/capabilities/k3kleict5ks3r4

The capability resource itself is not public, but it can be requested with its own URL in the Authorization header.

Collections API

In ActivityPub, ActivityStreams collections are frequently used to handle side-effects. For example, when a Follow activity is sent, the actor is added to the as:followers collection. Collections have their own paging system. They can be ordered or unordered. Also, they can dereference the items they contain (this is the case for the inbox) or only display their URIs (like the as:followers collection).

However, no API has been defined to create custom collections or add/remove items from existing collections.

Create custom collection

⚠️ Will be available in ActivityPods 2.0

In ActivityPods, ActivityStreams collections can be POSTed as regular LDP resources.

The @type can be a as:Collection or a as:OrderedCollection, depending on weither you need items to be ordered or not.

In the case of a as:OrderedCollection, you must also indicate the apods:sortField and apods:sortOrder.

We have added a boolean apods:dereferenceItems in order to declare if the items should be dereferenced or not.

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    { "apods": "http://activitypods.org/ns/core#", "dc": "http://purl.org/dc/terms/" }
  ],
  "@type": "OrderedCollection",
  "apods:sortField": "dc:created",
  "apods:sortOrder": "apods:AscOrder", // or "apods:DescOrder"
  "apods:dereferenceItems": true
}

There are discussions in the fediverse to specify these missing predicates.

Add or remove items

⚠️ Will be available in ActivityPods 2.0

It’s possible to add items to (or remove items from) a collection using the SparqlPatch method, the application/sparql-update Content-Type and a SPARQL query like this on the body:

PREFIX as: <https://www.w3.org/ns/activitystreams#>
INSERT DATA {
  <https://mypod.store/alice/followers> as:items <https://mypod.store/bob> .
};
DELETE DATA {
  <https://mypod.store/alice/followers> as:items <https://mypod.store/craig> .
}

For ordered collections, you should use the as:orderedItems predicate.

Notifications

⚠️ Will be available in ActivityPods 2.0

Apps can send notifications to Pod users like this:

{
  "type": "Note",
  "actor": "https://welcometomyplace.org/data/app",
  "name": "Alice invites you to an event: my birthday party !",
  "content": "You have received an invitation from Alice",
  "url": [
    {
      "type": "Link",
      "name": "View",
      "href": "https://welcometomyplace.org/Event/{eventUri}/show"
    },
    {
      "type": "Link",
      "name": "Ignore future Alice invitations",
      "href": "https://welcometomyplace.org/Event/{eventUri}/show?action=ignore"
    }
  ],
  "context": "https://mypod.store/alice/data/{uuid}"
}

They will be transformed into emails and, in the future, push notifications.

Applications can find the preferred language of an user by looking at the schema:knowsLanguage predicate on its WebID.

JsonLdContext header

It’s a peculiarity of the JSON-LD format that, when creating a LDP resource, you can indicate the context you wish to use (using the @context field), but when retrieving an existing resource, you are obliged to adapt to the context provided by the server. Of course, we can then reformat to suit our needs, but this may have performance costs.

This problem does not concern Solid providers who register data in the filesyste: they generally store and return the context provided at creation. However, when data is stored in a triple store, as is the case with ActivityPods, the initial context is lost.

To remedy this problem, all GET routes of our pods (whether for LDP resources, LDP containers or ActivityStreams collections) accept an optional JsonLdContext header, which can be either a URL or a JSON representation (of an array or object). As a result, the specified context will be used to format the returned JSON-LD data.

GET /alice/data/my-event HTTP/1.1
Host: example.org
Accept: application/ld+json
JsonLdContext: https://www.w3.org/ns/activitystreams
{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "https://example.org/alice/data/my-event",
  "type": "Event",
  "name": "My event"
}

There are discussions about using more standards headers.

Discovery

Identifying application actors

In ActivityPods, applications are also ActivityPub actor.

To find the actor linked with an application, we have implemented the FEP-2677