JSON-LDへの愚痴

次のような未知のJSONがソフトウェアに与えられたとき、

{
  "name": "Alice"
}

ソフトウェアは
"Alice"という値がなんであるかを識別することはできません。よって、nameという文字列キーの代わりに事前に定義された識別子を用いることにしましょう。例えば:
{
  "http://xmlns.com/foaf/0.1/name": "Alice"
}

(URLとして解釈可能な文字列ではありますが、これはたまたまです。URLとして機能するわけではありません。便宜上このような文字列を使っているというだけ。
ですのでそのURLのドメインが悪意ある第三者によって詐欺サイトにリダイレクトするようになっていても、JSON-LD的には問題ありません!

ここで、互換性のため
@contextというものを考えたいと思います。これを使って次のように書くと、
{
  "@context": {
    "name": "http://xmlns.com/foaf/0.1/name"
  },
  "name": "Alice"
}

@contextを無視するだけで、従来のソフトウェアは今まで通りにJSONを扱うことができます。これがJSON-LDの基本的なコンセプトです。

ちなみに
@contextではあらゆる識別子をあらゆる文字列へマッピングできます。よって、ソフトウェアは次の2種類のJSON-LDを同じように解釈する必要がありますね!
{
  "@context": {
    "name": "http://xmlns.com/foaf/0.1/name"
  },
  "name": "Alice"
}
{
  "@context": {
    "名前": "http://xmlns.com/foaf/0.1/name"
  },
  "名前": "Alice"
}

ではここでさらなる抽象化を考えてみましょう。次のようにすると、与えられたJSON-LDが人物の情報であることを表すことができます。
{
  "@context": "https://json-ld.org/contexts/person.jsonld",
  "name": "Alice"
}

コンテキストは複数指定することもできますし、従来の辞書型と混ぜることもできます。さらに、あるコンテキストで定義されたキーに別名を付けて使うこともできます。
{
  "@context": [
    "https://example.com/foo",
    "https://example.com/bar",
    {
      "buz": "https://example.com/buz",
      "qux": "buz:qux"
    }
  ]
}

そうそう、クラス定義というものもあります。次の例における
"Object"という文字列値は、Activity Vocabulary(ActiviyPubを構成する仕様の一つ)におけるObjectというクラスであることを示すものです。
{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "Object",
  "id": "http://www.test.example/object/1",
  "name": "A Simple, non-specific object"
}

Objectという文字列がキーとして使われることがないことはJSON-LDからは読み取れませんが、まあなんとかしてください!

ちなみにMisskeyが送信するJSONに付与する
@contextは次の通り。つまり、このコンテキストを理解できるソフトウェアを作れば、Misskeyと連携することができるということです。
{
	"@context": [
		"https://www.w3.org/ns/activitystreams",
		"https://w3id.org/security/v1",
		{
			"Key": "sec:Key",
			"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
			"sensitive": "as:sensitive",
			"Hashtag": "as:Hashtag",
			"quoteUrl": "as:quoteUrl",
			"toot": "http://joinmastodon.org/ns#",
			"Emoji": "toot:Emoji",
			"featured": "toot:featured",
			"discoverable": "toot:discoverable",
			"schema": "http://schema.org#",
			"PropertyValue": "schema:PropertyValue",
			"value": "schema:value",
			"misskey": "https://misskey-hub.net/ns#",
			"_misskey_content": "misskey:_misskey_content",
			"_misskey_quote": "misskey:_misskey_quote",
			"_misskey_reaction": "misskey:_misskey_reaction",
			"_misskey_votes": "misskey:_misskey_votes",
			"_misskey_summary": "misskey:_misskey_summary",
			"isCat": "misskey:isCat",
			"vcard": "http://www.w3.org/2006/vcard/ns#"
		}
	]
}

(ですがMisskeyは受信したJSON-LDをただのJSONとして解釈し、
@contextの内容は関知しません。)

そもそも情報交換用のサーバ間APIでJSON-LDのような柔軟で既存のJSON構造を壊さずに導入できる仕様を使う必要はないかもしれませんが……まあ細かいことは気にしない!

それでは、楽しいActivityPubサーバ開発を!!!

2

If you have a fediverse account, you can quote this note from your own instance. Search https://misskey.okayurisotto.net/notes/adldvkxhjv on your instance and quote it. (Note that quoting is not supported in Mastodon.)

このように複雑で厄介なJSON-LDの仕様を一つ一つ考慮しながらActivityPubソフトウェアを開発することに疲れたなら、Fedifyを使ってみてください。Fedifyは内部的に(JSON-LDを単なるJSONとして扱う実装ではなく)本格的なJSON-LDプロセッサを使用すると同時に、ハイレベルAPIではそれらをすべて抽象化し、JSON-LDを理解していなくてもActivityPubの開発を可能にします。

0