Copyright © 2017 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and permissive document license rules apply.
This document describes a JSON serialization format to describe simple streams of data as well as single objects of data for data transfer and processing.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.
This document was published by the Social Web Working Group as a Working Draft. Comments regarding this document are welcome. Please send them to public-socialweb@w3.org (subscribe, archives).
Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. The group does not expect this document to become a W3C Recommendation. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
This document is governed by the 1 March 2017 W3C Process Document.
This section is non-normative.
JF2 is a JSON based document format that describes lists and single entries of information. The primary use case for JF2 is to create a JSON format for social web post objects to be processed directly by client software and by other servers.
The name JF2 comes from its origins in being a direct parsed format of Microformats-2 (MF2) data from html. Rather than defining a new vocabulary, JF2 uses the vocabulary defined by [microformats2] however any other suitable vocabulary could be used. JF2 is vocabulary independent except for its profiles which are fully vocabulary aware.
This section is non-normative.
JF2 has evolved as a result of a variety of use-cases for different implementations exploring ways to simplify their existing use of canonical parsed microformats2 JSON output. All of these use cases in particular are simply to have a single format for the storage and use of social web objects.
Webmention.io is a service that provides webmention processing and verification on behalf of other sites. It uses a simple JSON object to transfer a processed webmention back to the client site's javascript for display. The attributes are intended to be processed only by the client site's javascript code, not by anything else.
mf2util is a utility library that provides a layer on top of microformats processing. The library returns only a simple JSON object and strips off any unnecessary information leaving the library user only the most essential information.
Various services (xray, unmung, socialstreams) provide conversion from microformats pages in to JF2 for quick inspection to validate proper semantics.
JF2 consists of JSON objects which are defined by a type property that will specify the vocabulary of the object. Properties are attached to these objects which will contain either a single string, a single object, an array of strings, or an array of objects. Arrays that have only a single item SHOULD be condensed into only the single containing item. Any property of an object MAY be a single item or an array of items except for reserved words defined below.
The following keywords are reserved and cannot be used as property names in vocabularies.
A post is composed of a "type" property, and one or more additional properties that describe the post.
The "type" property has a value that describes the vocabulary of this post. Common values include "entry", "card", etc. See Microformats 2 vocabularies for the full list when using a microformats based vocabulary.
Any additional properties in the post object are considered part of the post's vocabulary.
The list of valid post properties is defined by the vocabularies. This allows new vocabularies to be developed outside the development of the syntax.
Most values will be strings. If a property (such as `author` for example) references another object, it may be serialized in two ways: as an object serialized as the property value or as the unique identifier or URL where the object can be found. See Using References
Values may also be arrays if the vocabulary allows for multiple values of the property.
{
"type": "entry",
"published": "2015-10-20T15:49:00-0700",
"url": "http://example.com/post/fsjeuu8372",
"author": {
"type": "card",
"name": "Alice",
"url": "http://alice.example.com",
"photo": "http://alice.example.com/photo.jpg"
},
"name": "Hello World",
"content": "This is a blog post",
"category": "Posts"
}
{
"type": "entry",
"published": "2015-10-20T15:49:00-0700",
"url": "http://example.com/like/r23eugi02c",
"author": {
"type": "card",
"name": "Alice",
"url": "http://alice.example.com",
"photo": "http://alice.example.com/photo.jpg"
},
"like-of": "http://bob.example.com/post/100",
"category": ["Likes", "Posts"]
}
By default, any string value should be interpreted as literal plaintext. This means when displaying a string in an HTML page, it must be HTML escaped.
If the value of a property is to be interpreted as HTML, it MUST be enclosed in an object and placed under the "html" property as follows. If a plaintext version is also available, that is placed under the "text" property.
{
"type": "entry",
"content": {
"html": "<p>Hello World</p>"
"text": "Hello World"
}
}
Since HTML video/audio/picture tags may have multiple URLs, we need a way to convey this information in the JSON representation.
<div class="h-entry">
<video class="u-video" width="640" height="360" preload controls>
<source src="sample_h264.mov" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"' />
<source src="sample_ogg.ogv" type='video/ogg; codecs="theora, vorbis"' />
<source src="sample_webm.webm" type='video/webm; codecs="vp8, vorbis"' />
</video>
</div>
{
"type": "entry",
"video": [
{
"content-type": "video/mp4",
"url": "sample_h264.mov"
},
{
"content-type": "video/ogg",
"url": "sample_ogg.ogg"
},
{
"content-type": "video/webm",
"url": "sample_webm.webm"
}
]
}
The purpose of the `references` property is to exclude any non-authoritative data from the defined object. To do this, non-authoritative data is moved so that implementations looking to process only authoritative data may simply ignore the references property and fetch any data that would be contained there from its authoritative source.
If a property is a reference to an object that is defined authoritatively in some other location, the `references` property SHOULD be used. The property SHOULD contain only the unique identifier or URL where the authoritative data may be found. In the references object, the URL or unique identifier MAY be entered as the key field and a serialization of the referenced object MAY be provided. This serialization of the referenced object MAY be incomplete so as to provide only necessary data.
Parsing implementations SHOULD fetch data from the authoritative source instead of using the references object.
{
"type": "entry",
"published": "2015-10-20T15:49:00-0700",
"url": "http://example.com/post/fsjeuu8372",
"author": "http://alice.example.com",
"name": "Hello World",
"content": "This is a blog post",
"category": "Posts",
"references": {
"http://alice.example.com": {
"type": "card",
"name": "Alice",
"url": "http://alice.example.com",
"photo": "http://alice.example.com/photo.jpg"
}
}
}
{
"type": "entry",
"published": "2015-10-20T15:49:00-0700",
"url": "http://example.com/like/r23eugi02c",
"author": {
"type": "card",
"name": "Alice",
"url": "http://alice.example.com",
"photo": "http://alice.example.com/photo.jpg"
},
"like-of": "http://bob.example.com/post/100",
"category": ["Likes", "Posts"],
"references": {
"http://bob.example.com/post/100": {
"type": "entry",
"published": "2015-10-18T12:33:00-0700",
"url": "http://bob.example.com/post/100",
"author": "http://bob.example.com",
"name": "My First Post",
"content": "This is my first post on my new blog, I hope you like it"
},
"http://bob.example.com": {
"type": "card",
"name": "Bob",
"url": "http://bob.example.com",
"photo": "http://bob.example.com/mypicture.jpg"
}
}
}
Posts can live inside of collections. A collection may be a home page feed, or a feed of other posts such as a list of contacts, a list of things someone has liked, etc. There is no requirement that all posts in a collection need to be of the same type.
The collection may also have its own properties such as "name" or "author".
{
"type": "feed",
"url": "http://alice.example.com/collectionurl",
"name": "Alice's Home Page",
"author": {
"type": "card",
"name": "Alice",
"url": "http://alice.example.com",
"photo": "http://alice.example.com/photo"
},
"children": [
{ ... },
{ ... }
]
}
If an HTML page contains multiple top-level items, (most commonly found when a page contains a list of [h-entry] objects), the parser creates an implicit top-level collection with no properties.
{
"children": [
{ ... },
{ ... }
]
}
This syntax is derived from HTML with Microformats-2, converted to JSON [microformats2-parsing] converted to a simplified JSON. The examples below illustrate the process.
<article class="h-entry">
<h1 class="p-name">Hello World</h1>
<p>Published by <a class="p-author h-card" href="http://example.com/">A. Developer</a>
on <a href="http://example.com/2015/10/21" class="u-url"><time class="dt-published" datetime="2015-10-21T12:00:00-0700">October 21<sup>st</sup>, 2015</time></a>
<p class="p-summary">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus imperdiet ultrices pulvinar.</p>
<div class="e-content"><p>Donec dapibus enim lacus, <i>a vehicula magna bibendum non</i>. Phasellus id lacinia felis, vitae pellentesque enim. Sed at quam dui. Suspendisse accumsan, est id pulvinar consequat, urna ex tincidunt enim, nec sodales lectus nulla et augue. Cras venenatis vehicula molestie. Donec sagittis elit orci, sit amet egestas ex pharetra in.</p></div>
</article>
{
"items": [
{
"type": [
"h-entry"
],
"properties": {
"author": [
{
"type": [
"h-card"
],
"properties": {
"name": [
"A. Developer"
],
"url": [
"http:\/\/example.com\/"
]
},
"value": "A. Developer"
}
],
"name": [
"Hello World"
],
"summary": [
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus imperdiet ultrices pulvinar."
],
"url": [
"http:\/\/example.com\/2015\/10\/21"
],
"published": [
"2015-10-21T12:00:00-0700"
],
"content": [
{
"html": "<p>Donec dapibus enim lacus, <i>a vehicula magna bibendum non</i>. Phasellus id lacinia felis, vitae pellentesque enim. Sed at quam dui. Suspendisse accumsan, est id pulvinar consequat, urna ex tincidunt enim, nec sodales lectus nulla et augue. Cras venenatis vehicula molestie. Donec sagittis elit orci, sit amet egestas ex pharetra in.</p>",
"value": "Donec dapibus enim lacus, a vehicula magna bibendum non. Phasellus id lacinia felis, vitae pellentesque enim. Sed at quam dui. Suspendisse accumsan, est id pulvinar consequat, urna ex tincidunt enim, nec sodales lectus nulla et augue. Cras venenatis vehicula molestie. Donec sagittis elit orci, sit amet egestas ex pharetra in."
}
]
}
}
]
}
{
"type": "entry",
"author": {
"type": "card",
"url": "http://example.com",
"name": "A. Developer"
},
"url": "http://example.com/2015/10/21",
"published": "2015-10-21T12:00:00-0700",
"name": "Hello World",
"summary": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus imperdiet ultrices pulvinar.",
"content": {
"value": "<p>Donec dapibus enim lacus, <i>a vehicula magna bibendum non</i>. Phasellus id lacinia felis, vitae pellentesque enim. Sed at quam dui. Suspendisse accumsan, est id pulvinar consequat, urna ex tincidunt enim, nec sodales lectus nulla et augue. Cras venenatis vehicula molestie. Donec sagittis elit orci, sit amet egestas ex pharetra in.</p>",
"text": "Donec dapibus enim lacus, a vehicula magna bibendum non. Phasellus id lacinia felis, vitae pellentesque enim. Sed at quam dui. Suspendisse accumsan, est id pulvinar consequat, urna ex tincidunt enim, nec sodales lectus nulla et augue. Cras venenatis vehicula molestie. Donec sagittis elit orci, sit amet egestas ex pharetra in."
}
}
JF2 documents all have an implicit @context field which is optional. This @context can be found at http://www.w3.org/ns/jf2 and is provided only to make conversion to [JSON-LD] format possible. Most JF2 will process fine in JSON-LD systems, however, this support is not guaranteed and those wishing to use JF2 in JSON-LD may need to modify serialization slightly.
This section is non-normative.
JF2 on its own is intentionally vocabulary independent, that is, any value may contain a single value, a set of values, or a structure and there are no requirements that fields be present. While this keeps the fidelity of the original [microformats2] encoded html, some consuming code can be simplified by adding vocabulary requirements. This creates the need for vocabulary aware profiles of JF2, where the profile adds additional constraints on the fields present.
This section is non-normative.
XML formats have heavily dominated serializations of social activity feeds for blogs and news feeds for years. Several attempts have been created over the years to attempt to bring these to a JSON format, most recently [ jsonfeed-v1], which JF2 Feed gets the majority of its requirements from. JF2 Feed is an attempt to bring some of the advantages of these vocabulary aware specifications under a standard vocabulary from [ microformats2].
Fields described below have additional requirements to be considered a valid JF2 Feed, however they may contain any number of additional fields from [h-feed], [h-entry], and [h-card]. The entries below are codified as they are likely the most useful for feed readers and additional data is expected to be fetchable at the entry URL, preferrably though valid [microformats2] markup.
The following fields have additional constraints to be a valid JF2 Feed that only apply to the top level feed object, its child entry object, and any properties of them.
The format of published and updated fields may change from [ISO8601] to [RFC3339] or use [microformats2]'s more liberal date field. Please discuss on github issues
The JF2 Feed for a page may be published as HTTP Link header [RFC5988], or as an HTML <link> or <a> tag element with the following attributes.
rel="alternate" type="application/jf2feed+json" href="http://www.example.com/jf2feed.json"
Discovery via <link> and/or <a> is being considered for removal, please leave your feedback on this via github issues.
{
"type": "feed",
"url": "https://example.org/myfeed.html",
"name": "Brent Simmons’s Microblog",
"author": {
"type": "card",
"name": "Brent Simmons",
"url": "http://example.org/",
"photo": "https://example.org/avatar.png"
},
"children": [
{
"type": "entry",
"uid": "https://example.org/2347259",
"url": "https://example.org/2347259",
"content": {
"text": "Cats are neat. \n\nhttps://example.org/cats"
},
"published": "2016-02-09T14:22:00-07:00"
}
]
}
This section is non-normative.
As it is not sane to do this for every feed serialization currently available, this section is likely to only be temporary in the spec and may be moved to a more permanant home elsewhere.
JF2 Feed was based heavily on [jsonfeed-v1] and as such it is quite trivial to process a JSON Feed as a JF2 Feed with only minor changes. This section discusses the conversion that must be made for this process, most of which is simply conversion of properties to their [ microformats2] equivalent.
Conversion of the top level sturcture
Conversion of the author property on the top level or on any lower level entry
Conversion each entry in items
It may be benefitial to drop any properties other than those mentioned to avoid conflicts with any future [microformats2] properties.
JF2 MAY be extended by the [microformats2] extension mechanism. The 'x-*' properties created in this way MAY be present in any serialization of JF2. Parsers MUST NOT halt on any unknown properties they encounter.
This section is non-normative.
In order to allow any language to be serialized in JF2, the 'lang' value can be set on any object to inform annotate the natural language of the text. Many often ask for control structures like directionality of text and multiple language serializations. Directionality of text can be accomplished with UTF-8 control characters which can be added to any of the values in the document. In addition, any content inside of 'html' properties can have any markup as defined by [HTML5].
Multiple serializations of the same text has not been seen to be needed in practice. The suggested path for accomplishing this with JF2 is to have these hosted at different locations. For example, it is common practice on websites to host an alternate language version of a site under a different directory structure for each language (such as /en/, /jp/, /fr/, etc).
This section is non-normative.
The following is a list of currently known implementations of JF2-like formats and their current differences to this document
Webmention.io is a hosted service for handling webmentions. Webmentions are accessed from an API that that returns a set of objects in JSON format similar to JF2. The key difference is the inclusion of some additional data wrapping the objects (source, verified, verified_data, etc) and all wrapped in a "links" array. Code available at https://github.com/aaronpk/webmention.io
X-Ray is a tool to return structured data from any URL. Code available at https://github.com/aaronpk/XRay
Unmung is a tool for converting various formats. Code available at https://github.com/kevinmarks/unmung
Mf2util is a utility library for interpreting microformats2. Code available at https://github.com/kylewm/mf2util
As with any serialization format, JF2 streams can potentially contain private and personally identifiable information. As such, producing and consuming implementations SHOULD take a default stance that all information in these documents are private and take steps to ensure the privacy of their users. This can include transmission only over secure connections, limiting access to streams, deletion of stored secure information, or any other steps that would apply to any private information.
Publisher and Consumers of any publicly accessible or third party JF2 streams SHOULD take reasonable preventative measures to ensure against malicious code embedded in the stream and filter out such material wherever possible.
Publisher and Consumers of any publicly accessible or third party JF2 streams that contain HTML content SHOULD take additional steps to ensure that there is no malicious code such as cross-site scripting attacks contained in the HTML content.
JF2 Streams are JSON Documents and are subject to the same security considerations described in [RFC7159].
application/jf2feed+json
Media Type
This specification registers the application/jf2feed+json
MIME Media Type specifically for identifying documents conforming to the JF2 format with the JF2 Feed profile.
Type name: | application |
Subtype name: | jf2feed+json |
Required parameters: | None |
Optional parameters: | None |
Encoding considerations: | Binary, as per [RFC6839], section 3.1; the charset parameter is not used and byte-order marks are not permitted, as per [RFC7159], sections 11 and 8.1 |
Security considerations: | See [RFC7159] section 12 and the Security Considerations section of this specification. |
Contact: | Ben Roberts <ben@thatmustbe.me> |
This section lists changes from the 28 July 2016 FPWD to this version
The authors wish to thank the Microformats, IndieWebCamp, Pump.io, and Activity Streams communities for their continued work in building the social web and helping define standards such as this one. This includes, but is certainly not limited to, Aaron Parecki, Benjamin Goering, Brent Simmons, Christopher Webber, Dave Wilkinson II, James Snell, Jonathan LaCour, Kyle Mahan, Manton Reece, Pelle Wessman, and Tantek Çelik.
11.4 SocialStreams
SocialStreams is a translation service for converting social formats. Code available at https://github.com/dissolve/socialstream