chmod 777 @self
- open source, open standards, and the open web
2012-05-14
No more dynamic styles...
I've switched permanently back to a static template on the blog. The dynamic styles were flashy but slow, cumbersome beasts with all that javascript... like dressing up an elephant in a dress. I've picked a reasonable static template for now and will hopefully get around to making a few tweaks to it here and there soon.
2012-05-11
Iconography... and links
So here's a puzzler for you.
Within the IANA registry of Link Relations, we have this one link relation that is used to identify an icon. It is, creatively enough, called "icon". For instance,
Link: <http://example.org/res/icon.png>; rel="icon"
Seems simple enough, right? Well, what if we wanted to provide icons for different types of devices? Say, perhaps, an iOS App that runs on iPhone and iPad devices with and without the retina display... Before you answer that question, take a moment to review the iOS design guidelines here. While you're at it, swing over and take a look at the Android Design guidelines for icons also. The issue should be come apparent: how can I represent ALL the different kinds of icons possible for all the different kinds of devices and resolutions and purposes, etc.
Conventional wisdom, when using HTML, might be to make use of Media Queries... however, that's not a mechanism that is easily used in contexts outside of HTML... say Atom for instance, or JSON. Say, for instance, I want to be able to publish a JSON Activity Stream that provides a number of different usable icons for different screen resolutions. How would I do so in a way that is easily reproducible in a variety of contexts?
The simple answer is to expand on the general notion of an "icon" link relation, but add sizing information into the mix.
For example, it's theoretically possible to do this:
Link: <http://example.org/res/icon16.png>; rel="icon16x16",
<http://example.org/res/icon32.png>; rel="icon32x32",
<http://example.org/res/icon64.png>; rel="icon64x64"
and so on...
The main challenge with this, however, is that because of the rules of Link Relations defined in RFC 5988, in order to use a Link Relation like "icon16x16", it MUST be registered with the IANA Registry of Link Relations... not a terribly difficult thing to do, but it's also not something that scales well to handle the broad range (and apparently quite dynamic) range of icon sizes that are currently in use (there are something like 30+ sizes alone for iOS devices).
The other option, then, is to use an "Extension Link Relation", which, per RFC 5988, has to be an absolute URI reference... e.g. something along the lines of....
Link: <http://example.org/res/icon16.png>; rel="http://example.org/icon16x16",
<http://example.org/res/icon32.png>; rel="http://example.org/icon32x32",
<http://example.org/res/icon64.png>; rel="http://example.org/icon64x64"
So that would work; unfortunately it's rather cumbersome for people to have to work with that full http URI, especially when it's something that's not actually going to be dereferenced at any point. So can we do better? Perhaps we can through the use of a simple URN syntax...
Link: <http://example.org/res/icon16.png>; rel="urn:icon:16:16",
<http://example.org/res/icon32.png>; rel="urn:icon:32:32",
<http://example.org/res/icon64.png>; rel="urn:icon:64:64"
That's a bit better. So how about that JSON Activity Streams example? Well, I can make use of the new Links for Activity Streams draft I posted earlier this week to use these extension link relations directly within the JSON...
{
"actor": { ... },
"verb": "...",
"object": { ... },
"$urn:icon:16:16": "http://example.org/res/icon16.png",
"$urn:icon:32:32": "http://example.org/res/icon32.png",
"$urn:icon:64:64": "http://example.org/res/icon64.png"
}
Yes, it looks a bit odd at first, but there's really very little that a developer would need to know in order to work with this. First, to find an icon of any given size, it would merely look for a field named "$urn:icon:x:y" where x and y are the dimensions in pixels. In code, it would be simply object["$urn:icon:x:y"].
A nice thing about this approach is that the icon links would work across multiple formats... Link headers, atom:link elements, HTML Link and Anchor tags, JSON Activity Streams, etc. To me, that seems like a good thing.
Thoughts?
Within the IANA registry of Link Relations, we have this one link relation that is used to identify an icon. It is, creatively enough, called "icon". For instance,
Link: <http://example.org/res/icon.png>; rel="icon"
Seems simple enough, right? Well, what if we wanted to provide icons for different types of devices? Say, perhaps, an iOS App that runs on iPhone and iPad devices with and without the retina display... Before you answer that question, take a moment to review the iOS design guidelines here. While you're at it, swing over and take a look at the Android Design guidelines for icons also. The issue should be come apparent: how can I represent ALL the different kinds of icons possible for all the different kinds of devices and resolutions and purposes, etc.
Conventional wisdom, when using HTML, might be to make use of Media Queries... however, that's not a mechanism that is easily used in contexts outside of HTML... say Atom for instance, or JSON. Say, for instance, I want to be able to publish a JSON Activity Stream that provides a number of different usable icons for different screen resolutions. How would I do so in a way that is easily reproducible in a variety of contexts?
The simple answer is to expand on the general notion of an "icon" link relation, but add sizing information into the mix.
For example, it's theoretically possible to do this:
Link: <http://example.org/res/icon16.png>; rel="icon16x16",
<http://example.org/res/icon32.png>; rel="icon32x32",
<http://example.org/res/icon64.png>; rel="icon64x64"
and so on...
The main challenge with this, however, is that because of the rules of Link Relations defined in RFC 5988, in order to use a Link Relation like "icon16x16", it MUST be registered with the IANA Registry of Link Relations... not a terribly difficult thing to do, but it's also not something that scales well to handle the broad range (and apparently quite dynamic) range of icon sizes that are currently in use (there are something like 30+ sizes alone for iOS devices).
The other option, then, is to use an "Extension Link Relation", which, per RFC 5988, has to be an absolute URI reference... e.g. something along the lines of....
Link: <http://example.org/res/icon16.png>; rel="http://example.org/icon16x16",
<http://example.org/res/icon32.png>; rel="http://example.org/icon32x32",
<http://example.org/res/icon64.png>; rel="http://example.org/icon64x64"
So that would work; unfortunately it's rather cumbersome for people to have to work with that full http URI, especially when it's something that's not actually going to be dereferenced at any point. So can we do better? Perhaps we can through the use of a simple URN syntax...
Link: <http://example.org/res/icon16.png>; rel="urn:icon:16:16",
<http://example.org/res/icon32.png>; rel="urn:icon:32:32",
<http://example.org/res/icon64.png>; rel="urn:icon:64:64"
That's a bit better. So how about that JSON Activity Streams example? Well, I can make use of the new Links for Activity Streams draft I posted earlier this week to use these extension link relations directly within the JSON...
{
"actor": { ... },
"verb": "...",
"object": { ... },
"$urn:icon:16:16": "http://example.org/res/icon16.png",
"$urn:icon:32:32": "http://example.org/res/icon32.png",
"$urn:icon:64:64": "http://example.org/res/icon64.png"
}
Yes, it looks a bit odd at first, but there's really very little that a developer would need to know in order to work with this. First, to find an icon of any given size, it would merely look for a field named "$urn:icon:x:y" where x and y are the dimensions in pixels. In code, it would be simply object["$urn:icon:x:y"].
A nice thing about this approach is that the icon links would work across multiple formats... Link headers, atom:link elements, HTML Link and Anchor tags, JSON Activity Streams, etc. To me, that seems like a good thing.
Thoughts?
Update to the "Additional Link Relations" Draft
After talking it over with Erik Wilde (dret) I decided to update the "Additional Link Relations" Internet-Draft that I had published previously and remove the "implements" link relation in favor of using Erik's "profile" link relation to cover the same use cases.
Specifically, the "implements" link relation had been intended to provide information about what specifications a particular data representation or request message conformed to... it could, for instance, be used within the header of an HTTP request or response to indicate the protocol that the request/response conformed to.. e.g.
HTTP/1.1 200 OK
Content-Type: application/json
Link: <http://opensocial.org/specs/3.0>; rel="implements"
After reading through Erik's draft and speaking with him about it, it became clear that his "profile" link can cover the same case... so rather than have two overlapping link relations, we now have one...
HTTP/1.1 200 OK
Content-Type: application/json
Link: <http://opensocial.org/specs/3.0>; rel="profile"
Specifically, the "implements" link relation had been intended to provide information about what specifications a particular data representation or request message conformed to... it could, for instance, be used within the header of an HTTP request or response to indicate the protocol that the request/response conformed to.. e.g.
HTTP/1.1 200 OK
Content-Type: application/json
Link: <http://opensocial.org/specs/3.0>; rel="implements"
After reading through Erik's draft and speaking with him about it, it became clear that his "profile" link can cover the same case... so rather than have two overlapping link relations, we now have one...
HTTP/1.1 200 OK
Content-Type: application/json
Link: <http://opensocial.org/specs/3.0>; rel="profile"
2012-05-08
Activity Streams happenings...
There has been some recent discussion on the Activity Streams mailing list of introducing a few new verbs and object types that represent fairly common types of objects. Today I updated the draft of the Activity Streams Base Schema to include these new items...
The complete set of proposed base verbs specified by the schema specification is now... the new items are marked in bold... as you can see there are quite a few proposed new additions...
The complete list of proposed based object types is now.. the proposed new items are marked in bold.
Note that these are proposed changes and the schema document is still considered to be a draft. Additional changes are expected to be made as the community reviews and provides feedback.
These changes are intended to provide much more interesting activity scenarios... just as...
The complete set of proposed base verbs specified by the schema specification is now... the new items are marked in bold... as you can see there are quite a few proposed new additions...
| accept | Indicates that that the actor has accepted the object. For instance, a person accepting an award, or accepting an assignment. |
| access | Indicates that the actor has gained access to the object. |
| acknowledge | Indicates that the actor has acknowledged the object. This effectively signals that the actor is aware of the objects existence. |
| add | Indicates that the actor has added the object to the target. For instance, adding a photo to an album. |
| agree | Indicates that the actor agrees with the object. |
| append | Indicates that the actor has appended the object to the target. For instance, a person appending a new record to a database. |
| approve | Indicates that the actor has approved the object. For instance, a manager might approve a travel request. |
| archive | Indicates that the actor has archived the object. |
| assign | Indicates that the actor has assigned the object to the target. |
| at | Indicates that the actor is currently located at the object. For instance, a person being at a specific physical location. |
| attach | Indicates that the actor has attached the object to the target. For instance, a person attaching a file to a wiki page or an email. |
| attend | Indicates that the actor has attended the object. For instance, a person attending a meeting. |
| author | Indicates that the actor has authored the object. Note that this is a more specific form of the verb "create". |
| authorize | Indicates that the actor has authorized the object. If a target is specified, it means that the authorization is specifically in regards to the target. For instance, a service can authorize a person to access a given application; in which case the actor is the service, the object is the person, and the target is the application. In contrast, a person can authorize a request; in which case the actor is the person and the object is the request and there might be no explicit target. |
| borrow | Indicates that the actor has borrowed the object. If a target is specified, it identifies the entity from which the object was borrowed. For instance, if a person borrows a book from a library, the person is the actor, the book is the object and the library is the target. |
| build | Indicates that the actor has built the object. For example, if a person builds a model or compiles code. |
| cancel | Indicates that the actor has canceled the object. For instance, canceling a calendar event. |
| close | Indicates that the actor has closed the object. |
| complete | Indicates that the actor has completed the object. |
| confirm | Indicates that the actor has confirmed or agrees with the object. For instance, a software developer might confirm an issue reported against a product. |
| consume | Indicates that the actor has consumed the object. The specific meaning is dependent largely on the object's type. For instance, an actor may "consume" an audio object, indicating that the actor has listened to it; or an actor may "consume" a book, indicating that the book has been read. As such, the "consume" verb is a more generic form of other more specific verbs such as "read" and "play". |
| checkin | Indicates that the actor has checked-in to the object. For instance, a person checking-in to a Place. |
| close | Indicates that the actor has closed the object. For instance, the object could represent a ticket being tracked in an issue management system. |
| create | Indicates that the actor has created the object. |
| delete | Indicates that the actor has deleted the object. This implies, but does not require, the permanent destruction of the object. |
| deliver | Indicates that the actor has delivered the object. For example, delivering a package. |
| deny | Indicates that the actor has denied the object. For example, a manager may deny a travel request. |
| disagree | Indicates that the actor disagrees with the object. |
| dislike | Indicates that the actor dislikes the object. Note that the "dislike" verb is distinct from the "unlike" verb which connotates that the object had been previously "liked". |
| experience | Indicates that the actor has experienced the object in some manner. Note that, depending on the specific object types used for both the actor and object, the meaning of this verb can overlap that of the "consume" and "play" verbs. For instance, a person might "experience" a movie; or "play" the movie; or "consume" the movie. The "experience" verb SHOULD be considered a more generic form of other more specific verbs as "consume", "play", "watch", "listen", and "read" |
| favorite | Indicates that the actor marked the object as an item of special interest. |
| find | Indicates that the actor has found the object. If a target is specified, it SHOULD indicate where the object was found. |
| follow | Indicates that the actor began following the activity of the object. In most cases, the object will be a Person, but it can potentially be of any type that can sensibly generate activity. Processors MAY ignore (silently drop) successive identical "follow" activities. |
| give | Indicates that the actor is giving an object to the target. Examples include one person giving a badge object to another person. The object identifies the object being given. The target identifies the receiver. |
| host | Indicates that the actor is hosting the object. As in hosting an event, or hosting a service. |
| ignore | Indicates that the actor has ignored the object. For instance, this verb may be used when an actor has ignored a friend request, in which case the object may be therequest-friend activity. |
| insert | Indicates that the actor has inserted the object into the target. |
| install | Indicates that the actor has installed the object, as in installing an application. |
| interact | Indicates that the actor has interacted with the object. For instance, when one person interacts with another. |
| invite | Indicates that the actor has invited the object, typically a person object, to join or participate in the object described by the target. The target could, for instance, be an event, group or a service. |
| join | Indicates that the actor has become a member of the object. This specification only defines the meaning of this verb when its object is a group, though implementors SHOULD be prepared to handle other Object types as meaning MAY be provided by extension specifications. Processors MAY ignore (silently drop) successive identical "join" activities. |
| leave | Indicates that the actor has left the object. For instance, a Person leaving a Group or checking-out of a Place. |
| like | Indicates that the actor marked the object as an item of special interest. The "like" verb is considered to be an alias of "favorite". The two verb are semantically identical. |
| listen | Indicates that the actor has listened to the object. This is typically only applicable for objects representing audio content, such as music, and audio-book, or a radio broadcast. The "listen" verb is a more specific form of the "consume", "experience" and "play" verbs. |
| lose | Indicates that the actor has lost the object. For instance, if a person loses a game. |
| make-friend | Indicates the creation of a friendship that is reciprocated by the object. Since this verb implies an activity on the part of its object, processors MUST NOT accept activities with this verb unless they are able to verify through some external means that there is in fact a reciprocated connection. For example, a processor may have received a guarantee from a particular publisher that the publisher will only use this Verb in cases where a reciprocal relationship exists. |
| open | Indicates that the actor has opened the object. For instance, the object could represent a ticket being tracked in an issue management system. |
| play | Indicates that the actor spent some time enjoying the object. For example, if the object is a video this indicates that the subject watched all or part of the video. The "play" verb is a more specific form of the "consume" verb. |
| present | Indicates that the actor has presented the object. For instance, when a person gives a presentation at a conference. |
| purchase | Indicates that the actor has purchased the object. If a target is specified, in indicates the entity from which the object was purchased. |
| qualify | Indicates that the actor has qualified for the object. If a target is specified, it indicates the context within which the qualification applies. |
| read | Indicates that the actor read the object. This is typically only applicable for objects representing printed or written content, such as a book, a message or a comment. The "read" verb is a more specific form of the "consume", "experience" and "play" verbs. |
| receive | Indicates that the actor is receiving an object. Examples include a person receiving a badge object. The object identifies the object being received. |
| reject | Indicates that the actor has rejected the object. |
| remove | Indicates that the actor has removed the object from the target. |
| remove-friend | Indicates that the actor has removed the object from the collection of friends. |
| replace | Indicates that the actor has replaced the target with the object. |
| request | Indicates that the actor has requested the object. If a target is specified, it indicates the entity from which the object is being requested. |
| request-friend | Indicates the creation of a friendship that has not yet been reciprocated by the object. |
| resolve | Indicates that the actor has resolved the object. For instance, the object could represent a ticket being tracked in an issue management system. |
| return | Indicates that the actor has returned the object. If a target is specified, it indicates the entity to which the object was returned. |
| retract | Indicates that the actor has retracted the object. For instance, if an actor wishes to retract a previously published activity, the object would be the previously published activity that is being retracted. |
| rsvp-maybe | The "possible RSVP" verb indicates that the actor has made a possible RSVP for the object. This specification only defines the meaning of this verb when its object is an event (see Section 4.11), though implementors SHOULD be prepared to handle other object types as meaning MAY be provided by extension specifications. The use of this verb is only appropriate when the RSVP was created by an explicit action by the actor. It is not appropriate to use this verb when a user has been added as an attendee by an event organiser or administrator. |
| rsvp-no | The "negative RSVP" verb indicates that the actor has made a negative RSVP for the object. This specification only defines the meaning of this verb when its object is an event (see Section 4.11), though implementors SHOULD be prepared to handle other object types as meaning MAY be provided by extension specifications. The use of this verb is only appropriate when the RSVP was created by an explicit action by the actor. It is not appropriate to use this verb when a user has been added as an attendee by an event organiser or administrator. |
| rsvp-yes | The "positive RSVP" verb indicates that the actor has made a positive RSVP for an object. This specification only defines the meaning of this verb when its object is an event (see Section 4.11), though implementors SHOULD be prepared to handle other object types as meaning MAY be provided by extension specifications. The use of this verb is only appropriate when the RSVP was created by an explicit action by the actor. It is not appropriate to use this verb when a user has been added as an attendee by an event organiser or administrator. |
| satisfy | Indicates that the actor has satisfied the object. If a target is specified, it indicate the context within which the object was satisfied. For instance, if a person satisfies the requirements for a particular challenge, the person is the actor; the requirement is the object; and the challenge is the target. |
| save | Indicates that the actor has called out the object as being of interest primarily to him- or herself. Though this action MAY be shared publicly, the implication is that the object has been saved primarily for the actor's own benefit rather than to show it to others as would be indicated by the "share" verb. |
| schedule | Indicates that the actor has scheduled the object. For instance, scheduling a meeting. |
| search | Indicates that the actor is or has searched for the object. If a target is specified, it indicates the context within which the search is or has been conducted. |
| sell | Indicates that the actor has sold the object. If a target is specified, it indicates the entity to which the object was sold. |
| send | Indicates that the actor has sent the object. If a target is specified, it indicates the entity to which the object was sent. |
| share | Indicates that the actor has called out the object to readers. In most cases, the actor did not create the object being shared, but is instead drawing attention to it. |
| sponsor | Indicates that the actor has sponsored the object. If a target is specified, it indicates the context within which the sponsorship is offered. For instance, a company can sponsor an event; or an individual can sponsor a project; etc. |
| start | Indicates that the actor has started the object. For instance, when a person starts a project. |
| stop-following | Indicates that the actor has stopped following the object. |
| submit | Indicates that the actor has submitted the object. If a target is specified, it indicates the entity to which the object was submitted. |
| tag | Indicates that the actor has associated the object with the target. For example, if the actor specifies that a particular user appears in a photo. the object is the user and the target is the photo. |
| terminate | Indicates that the actor has terminated the object. |
| tie | Indicates that the actor has neither won or lost the object. This verb is generally only applicable when the object represents some form of competition, such as a game. |
| unfavorite | Indicates that the actor has removed the object from the collection of favorited items. |
| unlike | Indicates that the actor has removed the object from the collection of liked items. |
| unsatisfy | Indicates that the actor has not satisfied the object. If a target is specified, it indicates the context within which the object was not satisfied. For instance, if a person fails to satisfy the requirements of some particular challenge, the person is the actor; the requirement is the object and the challenge is the target. |
| unsave | Indicates that the actor has removed the object from the collection of saved items. |
| unshare | Indicates that the actor is no longer sharing the object. If a target is specified, it indicates the entity with whom the object is no longer being shared. |
| update | The "update" verb indicates that the actor has modified the object. Implementors SHOULD use verbs such as post where the actor is adding new items to a collection or similar. Update is reserved for modifications to existing objects or data such as changing a user's profile information. |
| use | Indicates that the actor has used the object in some manner. |
| watch | Indicates that the actor has watched the object. This verb is typically applicable only when the object represents dynamic, visible content such as a movie, a television show or a public performance. This verb is a more specific form of the verbs "experience", "play" and "consume". |
| won | Indicates that the actor has won the object. This verb is typically applicable only when the object represents some form of competition, such as a game. |
The complete list of proposed based object types is now.. the proposed new items are marked in bold.
- Alert
- Application
- Article
- Audio
- Badge
- Binary
- Bookmark
- Collection
- Comment
- Device
- Event
- File
- Game
- Group
- Image
- Job
- Note
- Offer
- Person
- Place
- Process
- Product
- Question
- Review
- Service
- Task
- Video
Note that these are proposed changes and the schema document is still considered to be a draft. Additional changes are expected to be made as the community reviews and provides feedback.
These changes are intended to provide much more interesting activity scenarios... just as...
- {actor} add {application} to {device}
- {actor} played {game}
- {actor} posted {offer}
- {actor} purchased {product} from {target}
- {actor} completed {task}
- {actor} assigned {task} to {person}
And so on...
I have also just posted a first draft of a Verb Definition mechanism for Activity Streams. The mechanism uses the Activity Streams format to provide a means of describing information about new verbs... for instance:
{
"objectType": "verb",
"displayName": "Send",
"id": "http://example.org/verbs/send",
"value": "http://example.org/verbs/send",
"synonyms": ["http://example.org/verbs/deliver"],
"hypernyms": ["give"],
"objects": [
{
"actor": "person",
"object": "note",
"target": "person",
"targetRequired": true,
"templates": {
"*": "{actor} sent {object} to {target}",
"de-*": "{actor} geschickt {target} das {object}",
}
},
{
"actor": "person",
"object": "note",
"templates": {
"*": "{actor} sent {object}",
"de-*": "{actor} geschickt {object}",
}
},
]
}
The idea is that implementors that wish to introduce new verbs into the ecosystem can use this format to do so; publishing them in accessible locations on a website and allowing implementations that consume Activity Streams to read them in and add the verbs to their known library of verbs. There are still many details to work out, to be certain, but this should give us a starting point to work from.
One of the key advantages of defining this as a Activity Streams object type is that we can then use an Activity Stream to talk about extension verbs used in the stream... for instance, imagine the following:
{
"items": [
{
"actor": {"displayName": "James"},
"verb": "create",
"object": {
"objectType":"verb",...,
"value":"http://example.org/verbs/foo"
}
},
{
"actor": {"displayName": "James"},
"verb": "http://example.org/verbs/foo",
"object": { ... }
}
]
}
I'm not yet convinced this kind of extensibility is as great as it looks on paper, but it is compelling to consider.
Anyway, as always, feedback is welcome and requested. Discussion on these topics should be directed to the Activity Streams mailing list. Details here.
2012-05-01
Linked Data using Link Relations
I've updated the Additional Link Relations draft with two additional Link Relations that should really have been obvious: "about" and "type"... these allow us to create RDF-style semantic statements about arbitrarily linked resources using the RFC 5988 Link model without actually using RDF... continuing on my previous theme of Mostly Linked Data.
For instance, suppose I have a resource that provides information about a particular user account identified as "http://people.example.org/user/~jasnell" and I want to specify that the information conforms to the Schema.org Person data model... the HTTP response message could be...
HTTP/1.1 200 OK
Content-Type: application/json
Link: <http://people.example.org/user/~jasnell>; rel="about",
<http://schema.org/Person>; rel="type"
{
// details about the person...
}
Because we're talking about links, I can use the same link relation in other places too... for instance, within an Activity Stream to say that a particular object is a type of schema.org Event...
{
...,
"object": {
"objectType": "event",
"$type": "http://schema.org/Event",
"$about": "http://events.example.com/event/1",
"id": "http://foo.example.org/123abcedf890",
...
}
}
Or within HTML, of course...
<a href="..." rel="about">...</a>
<link href="..." rel="type">...</a>
Let's imagine a core complex example that pulls pieces from lots of different places...
Suppose we have a document that is hosted at http://docs.example.org/dog.xml. This document:
For instance, suppose I have a resource that provides information about a particular user account identified as "http://people.example.org/user/~jasnell" and I want to specify that the information conforms to the Schema.org Person data model... the HTTP response message could be...
HTTP/1.1 200 OK
Content-Type: application/json
Link: <http://people.example.org/user/~jasnell>; rel="about",
<http://schema.org/Person>; rel="type"
{
// details about the person...
}
Because we're talking about links, I can use the same link relation in other places too... for instance, within an Activity Stream to say that a particular object is a type of schema.org Event...
{
...,
"object": {
"objectType": "event",
"$type": "http://schema.org/Event",
"$about": "http://events.example.com/event/1",
"id": "http://foo.example.org/123abcedf890",
...
}
}
Or within HTML, of course...
<a href="..." rel="about">...</a>
<link href="..." rel="type">...</a>
Let's imagine a core complex example that pulls pieces from lots of different places...
Suppose we have a document that is hosted at http://docs.example.org/dog.xml. This document:
- Is a Book (http://schema.org/Book)
- Is about Dogs (http://things.example.org/animals/canines/dog)
- Is serialized as XML (application/xml) that conforms to RFC 2629
- Can be edited using simple REST calls that conform to some theoretical standard (http://example.org/api/restedit)
- Is part of a larger collection of books identified as http://books.example.com/pets
When I send a HEAD request to the url... what I could get back is...
HTTP/1.1 200 OK
Content-Type: application/xml
Link: <http://schema.org/Book>; rel="type",
<http://things.example.org/animals/canines/dog>; rel="about",
<http://tools.ietf.org/html/rfc2629>; rel="profile",
<http://tools.ietf.org/html/rfc2629>; rel="implements",
<http://books.example.com/pets>; rel="collection"
2012-04-18
Thoughts on API design...
After spending the last two months working on fundamental rewrites to the core of the OpenSocial family of specifications in preparation for the 3.0 release towards the end of the year, I cannot agree enough with much of this post. The key quote comes in a comment... "companies are jumping into building APIs without [...] deep thought"
While Joshua Bloch's presentation on How to Design a Good API is prompting some good discussion, there is one particular point that I have to disagree with. On slide 2 he states, "Public APIs are forever - one chance to get it right". This isn't exactly true. Public APIs can be extremely fluid if done correctly. Backwards compatibility is important, to be sure, but given the right care and consideration and the right development approach, one shouldn't be afraid to simply throw old stuff away and start over, especially when the benefits of redesign and refactoring are clear.
While Joshua Bloch's presentation on How to Design a Good API is prompting some good discussion, there is one particular point that I have to disagree with. On slide 2 he states, "Public APIs are forever - one chance to get it right". This isn't exactly true. Public APIs can be extremely fluid if done correctly. Backwards compatibility is important, to be sure, but given the right care and consideration and the right development approach, one shouldn't be afraid to simply throw old stuff away and start over, especially when the benefits of redesign and refactoring are clear.
Even more on the future of MIME Media Types
So I decided to spend some time today seeing if I could flesh out some of the additional details on this hypothetical revamp of MIME Media Types... largely as a thought experiment to see how it would evolve... here's what I've got so far... This is all just public brainstorming at this point so the notes are a bit disjointed and unpolished. Bear with me. Comments and feedback are obviously quite welcome.
All data representation are essentially, at their core, a stream of bytes. Currently, we have the "application/octet-stream" media type that serves as a kind of default baseline for all other media types. If an application does not understand any given media type, it is supposed to fall back to handling it like it would handle "application/octet-stream". So let's make that our first baseline Content-Profile. We'll call it simply, "octet-stream".
HTTP/1.1 200 OK
Content-Profile: octet-stream
{some set of bytes}
This is exactly equivalent to setting Content-Type: application/octet-stream.
Let's take a step up from there. Let's assume that our stream of bytes represents US-ASCII character data. Let's suppose, for instance, that it's the simple message "Hello World". Today, we would represent this with Content-Type as...
HTTP/1.1 200 OK
Content-Type: text/plain
Hello World
The media type "text/plain" actually defines two distinct components.. "text" which identifies the content as character based and "plain" which identifies the content as having no formatting data or processing instructions what so ever. Let's separate these into distinct Content-Profile tokens... giving us...
HTTP/1.1 200 OK
Content-Profile: octet-stream, text, plain
Hello World
Right away we can see that things can get rather cumbersome with this approach, so let's state that every profile can have zero or more "assumed profiles".. for instance, we'll just say that everything is assumed to be "octet-stream" so we don't really have to declare that part in our Content-Profile field... also, "plain text" is generally considered a reasonable default given the lack of any additional information so let's just say that given...
HTTP/1.1 200 OK
Content-Profile: text
Hello World
... we can safely assume that we're talking about plain text.. the exact equivalent to "text/plain"
Let's throw another wrinkle into the mix. Let's suppose that our plain text is encoded as UTF-16. With media types currently, we have this charset parameter that is used to identify the encoding of character data within the entity. For instance "text/plain;charset=utf-16". My question is... why does it have to be a parameter? Let's just say that character encoding identifiers are are valid Content-Profile labels... therefore, if I want to say that this payload entity is equivalent to "text/plain;charset=utf-16".. I would simply say:
HTTP/1.1 200 OK
Content-Profile: text, utf-16
Hello World
Syntax wise, that's a hell of a lot clearer than "text/plain;charset=utf-16"... so far, so good...
Let's expand on this notion of assumed profiles... it may not make a lot of sense yet, but let's see how it plays out a bit... Right now in the media type registry, there are nine top level media types:
All data representation are essentially, at their core, a stream of bytes. Currently, we have the "application/octet-stream" media type that serves as a kind of default baseline for all other media types. If an application does not understand any given media type, it is supposed to fall back to handling it like it would handle "application/octet-stream". So let's make that our first baseline Content-Profile. We'll call it simply, "octet-stream".
HTTP/1.1 200 OK
Content-Profile: octet-stream
{some set of bytes}
This is exactly equivalent to setting Content-Type: application/octet-stream.
Let's take a step up from there. Let's assume that our stream of bytes represents US-ASCII character data. Let's suppose, for instance, that it's the simple message "Hello World". Today, we would represent this with Content-Type as...
HTTP/1.1 200 OK
Content-Type: text/plain
Hello World
The media type "text/plain" actually defines two distinct components.. "text" which identifies the content as character based and "plain" which identifies the content as having no formatting data or processing instructions what so ever. Let's separate these into distinct Content-Profile tokens... giving us...
HTTP/1.1 200 OK
Content-Profile: octet-stream, text, plain
Hello World
Right away we can see that things can get rather cumbersome with this approach, so let's state that every profile can have zero or more "assumed profiles".. for instance, we'll just say that everything is assumed to be "octet-stream" so we don't really have to declare that part in our Content-Profile field... also, "plain text" is generally considered a reasonable default given the lack of any additional information so let's just say that given...
HTTP/1.1 200 OK
Content-Profile: text
Hello World
... we can safely assume that we're talking about plain text.. the exact equivalent to "text/plain"
Let's throw another wrinkle into the mix. Let's suppose that our plain text is encoded as UTF-16. With media types currently, we have this charset parameter that is used to identify the encoding of character data within the entity. For instance "text/plain;charset=utf-16". My question is... why does it have to be a parameter? Let's just say that character encoding identifiers are are valid Content-Profile labels... therefore, if I want to say that this payload entity is equivalent to "text/plain;charset=utf-16".. I would simply say:
HTTP/1.1 200 OK
Content-Profile: text, utf-16
Hello World
Syntax wise, that's a hell of a lot clearer than "text/plain;charset=utf-16"... so far, so good...
Let's expand on this notion of assumed profiles... it may not make a lot of sense yet, but let's see how it plays out a bit... Right now in the media type registry, there are nine top level media types:
- application
- audio
- example
- image
- message
- model
- multipart
- text
- video
Each of these is further divided into registries of sub-types that inherit properties of the top level type and specify additional semantics on top. Let's define that each of these top level types, and each of their subtypes, will become individual Content-Profile identifiers. For instance, whereas we now have the media type "image/jpeg" to identify jpeg images, with the Content-Profile approach, we would have "image" and "jpeg" as distinct profile identifiers, where "image" is an assumed profile of "jpeg"... Ok, that's clear as mud... Here's the breakdown.. the following are equivalent:
- Content-Type: image/jpeg
- Content-Profile: octet-stream, application, image, jpeg
- Content-Profile: application, image, jpeg
- Content-Profile: image, jpeg
- Content-Profile: jpeg
How this breaks down is simple: if we understand what "jpeg" is, we'll understand that it's an image resource.. the "image" profile is assumed. Likewise, we can assume the "application" and "octet-stream" profiles as well... We wouldn't need to write "image/jpeg" all the time, just "jpeg". Of course, if we're using a less well known image format and we're afraid that some application down the line doesn't know how to handle it, then we'd probably want to stick with using "image, jpeg", just to be safe.
Let's look at a more difficult example... MPEG-4 video and audio. In media types, they are identified as "video/mp4" and "audio/mp4"... with Content-Profile, these would be represented as:
- Content-Profile: video, mp4 or just Content-Profile: mp4
- Content-Profile: audio, mp4
By default, "video" would be an assumed profile for the "mp4" profile since that's the most common case... which means that unless "audio" is explicitly specified, the application would assume that it's dealing with video/mp4 content.
Let's assume an even more difficult example... multipart media types... currently there are 14 separate multipart subtypes registered within the IANA registry. Each of these would become a distinct profile. For each, there is a requirement that we identify the boundary delimiter and other parameters such as the ID of the starting part, etc.
For instance, let's suppose I have a multipart/related structure. The MIME Media Type would be like: multipart/related; boundary=foo-1; start="<cid:foo>"; type="text/plain"
Assuming "multipart" is an assumed profile of "related", the equivalent Content-Profile would be:
- Content-Profile: related; boundary=foo-1; start="<cid:foo>"; profile="text"
Now let's get a bit crazy with it... let's assume we're talking about Atom (RFC4287). Right now, the MIME Media Type for Atom is "application/atom+xml". If we need to further differentiate between Entry and Feed documents, it's "application/atom+xml; type=entry" and "application/atom+xml; type=feed", respectively. There's actually four distinct pieces of info in each of those: application, xml, atom and (entry or feed). Let's break each of those out into distinct profile identifiers such that "application" is an assumed profile of "xml" which is an assumed profile of "atom"...
The equivalent of "application/atom+xml; type=entry" would become:
- Content-Profile: atom, entry
The equivalent of "application/atom+xml; type=feed" would become:
- Content-Profile: atom, feed
If I was worried that someone who doesn't know about Atom may attempt to process this thing, then I can throw in the "xml" just to be safe...
- Content-Profile: xml, atom, feed
Oh, suppose we also needed to specify the charset encoding... The equivalent of "application/atom+xml; type=feed; charset=UTF-8" would become, simply:
- Content-Profile: xml, atom, feed, utf-8
Now let's suppose that I wanted to say that this particular Atom feed conformed to, say, the Atom Activity Streams spec... and let's suppose that's not an IANA registered profile; it's just a spec out there that defines a profile identifier of "http://activitystrea.ms/specs/atom/1.0/"... With Content-Type, there's no way we can currently specify this information without minting a new media type subset of +xml ... with Content-Profile, however, it becomes simply:
- Content-Profile: xml, atom, feed, utf-8, http://activitystrea.ms/specs/atom/1.0/
This gives us everything I need to know. If I needed to specify additional profiles, I could simply tack them on to the end. I wouldn't even need to register those things. It would be completely decentralized and extensible.
Hmm... looking good so far.. but let's explore it further. MIME Media Types are generally used to associate specific content types with applications capable of handling those types. For instance, within the Android operating system, media types are used to help determine how particular bits of content are to be routed around and handled. In the form of intents. Web browsers can associate applications with specific media types such that when you download a PDF, for instance, it can route the document to an application capable of displaying it, etc. Would we still be able to achieve that same goal with Content-Profile? Essentially: yes, we would.
Consider this snippet of XML from an Android application's Manifest file:
<intent-filter . . . >
<data android:mimeType="video/*" android:scheme="http" . . . />
<data android:mimeType="audio/*" android:scheme="http" . . . />
. . .
</intent-filter>
Note the data elements with the android:mimeType property specifying the MIME Media type ranges... using a Content-Profile as an alternative, this could become:
<intent-filter . . . >
<data android:profile="video" android:scheme="http" . . . />
<data android:profile="audio" android:scheme="http" . . . />
. . .
</intent-filter>
The filter would match any type of content using the video or audio profiles. So that works...
Let's look at a another scenario where media types are used... One practical case.. imagine you have an Atom document with a bunch of atom:link elements that use rel="icon". Each link element identifies a different sized icon (perhaps the support all the different options that fancy new ipad retina display requires).. Right now, we'd have this:
<entry>
<link rel="icon" href=".../img1.png" type="image/png" />
<link rel="icon" href=".../img2.png" type="image/png" />
<link rel="icon" href=".../img3.png" type="image/png" />
</entry>
Currently, within Atom links and related mechanisms such as the Web Link header, we don't really have a mechanism for differentiating between different sized icons. One option is to register new link relations that identify each size... for instance,
<entry>
<link rel="icon16" href=".../img1.png" type="image/png" />
<link rel="icon32" href=".../img2.png" type="image/png" />
<link rel="icon64" href=".../img3.png" type="image/png" />
</entry>
Content-Profile presents another possible option...
<entry>
<link rel="icon" href=".../img1.png" profile="image,png,icon16" />
<link rel="icon" href=".../img2.png" profile="image,png,icon32" />
<link rel="icon" href=".../img3.png" profile="image,png,icon64" />
</entry>
Either approach would work in this case...
For now, I'm going to stop there and pick up the thread again tomorrow...
Subscribe to:
Posts (Atom)