wiki.trwnh.com/content/tech/spec/activitypub/confusion/accept-content-type.md

7.4 KiB

+++ autonumbering = true +++

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 the application/ld+json; profile="https://www.w3.org/ns/activitystreams" media type as being equivalent to application/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 of application/ld+json; profile="https://www.w3.org/ns/activitystreams". Servers SHOULD interpret a Content-Type or Accept header of application/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 to application/activity+json as well. The client MUST specify an Accept header with the application/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 expanded
  • http://www.w3.org/ns/json-ld#compacted to request or respond with data that has been compacted
  • http://www.w3.org/ns/json-ld#flattened to request or respond with data that has been flattened
  • http://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. The application/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 using application/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 as application/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:

  1. text/plain;format=flowed
  2. text/plain
  3. text/*
  4. */*

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