interpretation of request/response media types in as2/ap
AS2-Core says
An Activity Streams Document is a JSON document whose root value is an Activity Streams Object of any type […] and whose MIME media type is
application/activity+json
[…] Implementations SHOULD consider theapplication/ld+json; profile="https://www.w3.org/ns/activitystreams"
media type as being equivalent toapplication/activity+json
.
AP says
POST requests (eg. to the inbox) MUST be made with a Content-Type of
application/ld+json; profile="https://www.w3.org/ns/activitystreams"
and GET requests with an Accept header ofapplication/ld+json; profile="https://www.w3.org/ns/activitystreams"
. Servers SHOULD interpret a Content-Type or Accept header ofapplication/activity+json
as equivalent
MUST present the ActivityStreams object representation in response to
application/ld+json; profile="https://www.w3.org/ns/activitystreams"
, and SHOULD also present the ActivityStreams representation in response toapplication/activity+json
as well. The client MUST specify an Accept header with theapplication/ld+json; profile="https://www.w3.org/ns/activitystreams"
media type in order to retrieve the activity
basically as2 prefers activity+json while ap prefers ld+json with the activitystreams profile. ap is an extension to as2 so i guess ap takes precedence here…
conclusion A: request ld+json, respond activity+json?
taken literally and strictly, i interpret it like so:
- ap must request ld+json
- old as2 may request activity+json
and on the response side:
- return activity+json regardless of request type? since as2-core specifies that type for an “activity streams document”
- alternatively, return whatever type was requested. this is less likely to break expectations or otherwise false assumptions.
conclusion B: the semantics of json-ld profiles
you could also interpret a semantic difference between the two?
ld+json registration has 6 defined profiles: https://www.iana.org/assignments/media-types/application/ld+json
4 of these are the different forms of json-ld
http://www.w3.org/ns/json-ld#expanded
to request or respond with data that has been expandedhttp://www.w3.org/ns/json-ld#compacted
to request or respond with data that has been compactedhttp://www.w3.org/ns/json-ld#flattened
to request or respond with data that has been flattenedhttp://www.w3.org/ns/json-ld#framed
to request or respond with data that has been framed
there are also 2 utility profiles
http://www.w3.org/ns/json-ld#frame
to request or respond with a frame (that can be applied to data)http://www.w3.org/ns/json-ld#context
to request or respond with a context document
so then, what is the activitystreams profile? it’s not explicitly defined in either as2-core or in ap. but we can assume it has something to do with the extra restrictions and requirements that as2 adds on top of json-ld – that the document must be compacted against the activitystreams context at minimum.
@context may be missing in activity+json?
there’s also this bit from as2-core:
When a JSON-LD enabled Activity Streams 2.0 implementation encounters a JSON document identified using the
application/activity+json
MIME media type, and that document does not contain a @context property whose value includes a reference to the normative Activity Streams 2.0 JSON-LD @context definition, the implementation MUST assume that the normative @context definition still applies.
so basically ld-aware as2 implementations MUST inject the as2 context if it is missing from activity+json. but the reverse implication is what’s interesting here – activity+json means that context isn’t required!
also from as2-core:
Implementations producing Activity Streams 2.0 documents SHOULD include a @context property with a value that includes a reference to the normative Activity Streams 2.0 JSON-LD @context definition using the URL
https://www.w3.org/ns/activitystreams
.
note that this is only a SHOULD.
as2 author james snell explains further: https://github.com/w3c/activitystreams/issues/132#issuecomment-106854283
You can still use
application/ld+json
if you wish. Theapplication/activity+json
media type implies a very specific profile of JSON-LD – that is, JSON-LD in compacted form using the normative context definition. When usingapplication/activity+json
, the context can be implicit if you’re not using any extensions.
further comments from the issue:
AS2 is not just JSON-LD, it’s JSON-LD plus a number of additional constraints. The
application/activity+json
media type is used to indicate that those additional constraints are in effect. Yes, you can still treat it as straightforward JSON-LD, and yes, it’s best if implementers make the @context explicit in order to maximize interoperability with existing JSON-LD stacks as well as performance, but when the document is served up asapplication/activity+json
, there are certain assumptions that can be made.
markus lanthaler concludes:
Yes, you can still treat it as straightforward JSON-LD
No, you can’t if there’s no explicit context.
supporting generic json-ld consumers is a choice
it can be said that plain-json as2-native software may generate activity+json documents that are not compatible with json-ld. this gives as2 the dubious ability to be “json only”.
it can also be said that generic json-ld consumers may not recognize the activity+json type and may strictly require ld+json… although they shouldn’t. but they might.
so, the real problem is for generic json-ld software which has no idea what activitystreams is. to play nice with this kind of software, as2-core says you SHOULD include the as2 context. but this ends up being a choice because it’s only a SHOULD and not a MUST.
aside from that, the whole type debate is largely irrelevant for software which is activity-aware or activity-native (since you are recommended to treat the two as equivalent).
both are equivalent (and used in practice!)
HOWEVER: in practice, you will probably need to be able to handle both types in both request+response
impls that GET with activity+json:
- …
impls that GET with ld+json:
- …
impls that POST with activity+json:
- mastodon
impls that POST with ld+json:
- pixelfed
impls that return activity+json:
- mastodon
- pleroma
impls that return ld+json:
- misskey
- pixelfed
QUIRK: multiple types
ALSO NOTE: you may encounter multiple accept/content-type values. mastodon for example makes GET requests with Accept: application/activity+json, application/ld+json
(in violation of the activitypub spec) or Accept: application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams", text/html;q=0.1
(also in violation of activitypub). these are still valid by RFC 9110 “HTTP Semantics” Accept:
header parsing rules. note that multiple types are separated by a comma (,
) but you must not parse them in order; you parse them by most specific type first.
for example:
Accept: text/*, text/plain, text/plain;format=flowed, */*
[has] the following precedence:
- text/plain;format=flowed
- text/plain
- text/*
- */*
fwiw mastodon doesn’t seem interested in changing this so you will have to Deal With It if you care about mastodon compat https://github.com/mastodon/mastodon/pull/22722
see also
- SocialWG: Media type for AS2 https://www.w3.org/wiki/Socialwg/Media_type_for_AS2 – a discussion from when AS2 was being written.