Revision 1031 5/27/2008The RESTful API serves as a common protocol understood by all OpenSocial 0.8-compliant clients and servers. It replaces the November 2007 OpenSocial Data API proposal (which was based on the Google Data APIs). 0. Notation and ConventionsThe key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in [RFC2119]. Domain name examples use [RFC2606].1. OverviewThis API defines a language- and platform- neutral protocol for clients to interact with OpenSocial container servers outside of gadgets on a web page. As a protocol, it is intended to be reasonably easy to implement in any language and on any platform. It should also be usable across a range of clients, from gadgets operating within a web page to servers communicating to synchronize data about a user. The protocol operates primarily in terms of resources and operations on them. It is defined on top of the HTTP protocol, and uses the standard HTTP methods (GET, POST, PUT, DELETE, etc.) to retrieve and change server state. No single data representation is ideal for every client. This protocol defines dual representations for each resource in two widely supported formats, JSON [RFC4627] and Atom/AtomPub [RFC4287][RFC5023], using a set of generic mapping rules. The mapping rules allow a server to write to a single interface rather than implementing the protocol twice. OpenSocial container servers are free to define additional representations but MUST support at least the JSON and Atom formats defined in this document. The protocol defines Activity, Person, Group, and AppData resources and collections (resources which consist of a set of other resources). Most operations consist of retrieving (GET), updating (PUT), creating (POST or PUT), or destroying (DELETE) these resources. The protocol provides an optional feature to batch multiple requests together in a pipeline to avoid multiple HTTP round trips. Finally, it specifies an optional partial update feature which avoids sending large resources over the wire to update just one field. OpenSocial API Background details the underlying concepts used below; this document assumes familiarity with the OpenSocial model. 2. Data RepresentationsEach resource has a two representations, as JSON and Atom (XML). All data must be representable in both formats, but we do not attempt to map from generic XML or Atom to JSON. Instead, we define an internal data model using English and JSON syntax, and then define the mappings between this and Atom/JSON. Each resource is represented as a hierarchical tree of elements. Ordering of elements within a parent element may or may not be significant, depending on the context. Mapping consists of converting between the internal hierarchy and the JSON / Atom protocol format. The set of allowed fields in each type of data is the same as the set documented in the OpenSocial 0.8 API reference. The standard sets of fields are the same between the RESTful API and the JS APIs. The general rules for mapping between the Atom and JSON formats are as follows. Each data type may add additional aliasing rules.
Examples of the primary types of data follow. Each example shows both representations, JSON and Atom, with the payload data highlighted for ease of comparison. 2.1 CollectionsCollections are a useful abstraction for dealing generically with multiple things, whether those things are persons, groups, activities, or application data sets. They have both Atom and JSON representations; the Atom representation is simply a standard Atom feed whose entries are one of the entry types specified above. The default JSON collection representation is a JSON object containing an "entry" slot containing a list of JSON objects. Collections use the OpenSearch conventions for reporting totalResults (for complete unpaged feed), startIndex of current page, and itemsPerPage. For example: application/json representation: {
application/atom+xml representation: <feed xmlns="http://www.w3.org/2005/Atom" xmlns:osearch="http://a9.com/-/spec/opensearch/1.1"> Note: The standard "next" link in each case allows for paginated collections without the need to support full random access; collections MAY also support randomly accessed pages via query parameters. Activity stream collections are ordered chronologically by default, most recent activities first; containers MAY by default order other collections arbitrarily. Other orderings can be requested for collections using query parameters. 2.2 PersonA Person contains a social network oriented data about a single person. The same record is used for contacts/friends and for profiles. See the Person Fields API doc for a full list of available fields and their (JS) types. See also the general mapping rules in section 2. A minimal Person example: application/json representation: {
application/atom+xml representation: <entry xmlns="http://www.w3.org/2005/Atom"> Note: In general clients can ask for a full representation of a resource, with all fields and sub-fields, or a partial representation, using query parameters; see below for details. Note: The atom:summary element is the appropriate place to put a text or HTML representation of the structured data present in the content element, and the atom:title element is the appropriate place to copy a short descriptive name for the entry, such as name.unstructured. Servers MAY choose to add these or other fields to make their feeds more useful for generic aggregators or tools. 2.3 GroupOpenSocial Groups are owned by people, and are used to tag or categorize people and their relationships. The RESTful API supports querying for the available groups for a given user. The groups are returned as a collection. Each group has a display name, an identifier which is unique within the groups owned by that person, and a URI link. A Group example:
application/atom+xml representation: <entry xmlns="http://www.w3.org/2005/Atom"> Groups only appear within Group Collections and are used to retrieve a list of available groups for a given person. 2.4 ActivityAn OpenSocial Activity represents a short summary or notification of a timestamped event, often with pointers for more information. See the Activity Fields API doc for a full list of available fields and their (JS) types. Activities have extensive hoisting rules to ensure maximum compatibility with standard feed processing code:
A minimal Activity example: application/json representation: {
application/atom+xml representation: <entry xmlns="http://www.w3.org/2005/Atom"> 2.5 AppDataAppData stores uninterpreted key/value pairs on behalf of an application. The standard unit of AppData is all of the key/value pairs stored for a given app on behalf of a given user; however, the API supports other types of queries (detailed below). To retrieve a subset of fields, use the fields= selector syntax (detailed below). An isolated AppData example The first example is of a collection of key/value pairs for a particular application/user pair:
application/atom+xml representation: <entry xmlns="http://www.w3.org/2005/Atom"> An AppData Collection Example In this example, a client has requested a collection of data that spans multiple users. The result is a collection which, by default, is given a special default JSON representation as a mapping from users to their data. It's also possible to get a generic representation as an array using a query parameter: application/json default array representation: {
application/json representation (with indexBy=id): {
The default representation of a collection is simply a JSON list of records ([ {...}, {....}, ...]). The special type "index" means that the collection is instead to be represented as a mapping, using the index field; this is requested by supplying a query parameter "indexBy" (see above). The data within each field is assumed to be in JSON format and is otherwise uninterpreted. 3. OperationsOpenSocial uses standard HTTP methods: GET to retrieve, PUT to update in place, POST to create new, and DELETE to remove. POST is special; it operates on collections and creates new activities, persons, or app data within those collections, and returns the base URI for the created resource in the Location: header, per AtomPub semantics. Restricted clients, or clients behind restricted clients, which cannot use PUT or DELETE SHOULD translate PUT and DELETE to POST operations with an additional X-HTTP-Method-Override: header: POST /... HTTP/1.1 Servers SHOULD respond to POST+X-HTTP-Method-Override as if the content of the header were the actual operation sent. Note: OpenSocial 0.8 does not support cross-domain JSONP (GET with callback), but servers MAY offer this as an extension. It is RECOMMENDED that such servers implement appropriate security and authorization controls. 4. Request Authentication and Authorization ContextEach RESTful operation has a request context that usually includes authentication and authorization information. Typically, the context information includes the requestor id (the user initiating the request) and app ID (the application, or whatever is acting as the user's agent). It may include other container-specific information. Containers MUST be an OAuth Core 1.0 Service Provider (a web application that allows access via OAuth). Containers MAY also support other ways to establish a request context. Containers MUST also support the Consumer Request OAuth extension, in which the end user has not directly authorized the operation. Applications SHOULD ensure that the users have given prior consent, implicitly or explicitly, to the operation or class of operations. However, containers MAY require an additional prior trust relationship be established by the app in order to allow use of Consumer Request OAuth. If a Consumer has a user identifier and wishes to indicate that the operation is being done on behalf of that particular user, it SHOULD provide the OAuth extension parameter xoauth_requestor_id with the OAuth signed parameters. Consumers SHOULD only provide this if the user has given prior consent, implicitly or explicitly, to the operation or class of operations, as it indicates that the operation is being done on behalf of the user. Container SPs MUST either honor the parameter or ignore it as if it were not provided. Thus, a request context usually includes the requesting application (the OAuth Consumer), and may include the requesting user, either implicitly via an oauth_token or explicitly via xoauth_requestor_id. It may also include additional information via extensions or other channels (cookies, URI parameters, client SSL certificates, etc.) A container may also accept requests with no authentication or authorization (authnz) information at all for public data. A container may provide a public version (e.g., of a profile) if no authnz information is provided. Note that the data provided for a given RESTful URI MAY vary per requestor or app. Thus, the meaning of the resource at a given URI is "the view of the information available to the current requestor/app combination". In the case where no information is available due to lack of authorization, an HTTP 401 Unauthorized response SHOULD be returned to the client. In the case where at least some view of the information is available, it SHOULD be returned using a 200 status, with a standard OAuth WWW-Authenticate: header indicating that additional information may be available when using a different authnz context. 5. DiscoveryA container declares what collection and features it supports, and provides templates for discovering them, via a simple discovery document. A client starts the discovery process at the container's identifier URI (e.g., example.org). The full flow is available at http://xrds-simple.net/core/1.0/; in a nutshell:
The discovery document is an XML file in the same format used for OpenID and OAuth discovery, defined at http://xrds-simple.net/core/1.0/: <XRDS xmlns="xri://$xrds"> Each Service advertises a service provided by the container. Each container MUST support the service Types documented below and MAY support others by advertising them in the discovery document. Each service comprises a set of resources defined by the given URI Template (or URI, if there is only a single resource). Clients follow the URIs and instantiate the templates to find and operate on specific resources. (URI Template syntax is documented at http://www.ietf.org/internet-drafts/draft-gregorio-uritemplate-03.txt.) The set of substitution variables is fixed for each service Type. The core set of service Types and their substitution variables is documented below. Extensions to OpenSocial SHOULD document their substitution variables; note that a reasonable place to put human readable documentation is at the namespace URI. 6. The Core OpenSocial Service TypesThis section defines the core types that every OpenSocial container MUST support, their XRDS types, and their semantics. Unless otherwise specified, all HTTP operations are generally allowed for any URI endpoint; a container which wishes to specify the allowed operations SHOULD provide an HTTP Allow: header for each resource listing the allowed operations. 6.1 PeopleXRDS Type: http://ns.opensocial.org/people/0.8 guid : Container-globally-unique user identifier; identifies owner of the people data, or @me to indicate the requestor should be used selector : One of
People URI examples: Note that a given container may use alternative URI formats; for example, /people.cgi?guid={guid}&groupid={groupid}
is a valid URI pattern given the appropriate XRDS discovery document which allows clients to map the parameters to a concrete URI. Friends may be added by POSTing to the appropriate collection (e.g., /people/{guid}/@friends). Containers MAY require a dual opt-in process before the friend record appears in the collection, and in this case SHOULD return a 202 Accepted response, indicating that the request is 'in flight' and may or may not be ultimately successful. 6.2 GroupsXRDS Type: http://ns.opensocial.org/groups/0.8 guid : Container-globally-unique user identifier; identifies owner of the people data; can be @me to indicate auth[nz] requestor should be used. Groups URI examples: /groups/{guid} -- Collection of groups associated with user {guid}
6.3 ActivitiesXRDS Type: http://ns.opensocial.org/activities/0.8 guid : Container-globally-unique user identifier; owner or recipient of the activity data, or @me to indicate the requestor should be used selector : One of
Activity URI examples: /activities/{guid}/@self -- Collection of activities generated by given user
6.4 AppData (http://ns.opensocial.org/appdata/0.8)guid : Container-globally-unique user identifier, or @me to indicate the requestor should be used selector : One of
AppData URI examples: /appdata/{guid}/@self/{appid} -- All app data for user {guid}, app {appid}
6.5 Standard Query ParametersThese additional query parameters may be used with any URI above. The parameters startIndex and count are interpreted according to the OpenSearch spec. format={format} -- Format desired; one of (atom, json); default is json if not provided
7. Security ConsiderationsContainers SHOULD carefully consider security. Containers MUST support OAuth but SHOULD use appropriate policies to determine allowed operations on a per-Consumer and per-user basis. Per the OAuth spec, Containers SHOULD document how a Consumer can direct a user to a Container web page to obtain an oauth_token for future use. Note that this is a vector for phishing if the user is required to enter their credentials. Containers SHOULD support SSL connections for sensitive data as OAuth on its own does not provide encryption or message body integrity checking. Containers should base their security decisions on the type of client in use; a generally available desktop client, for example, cannot effectively protect a Consumer Secret that is installed with each client. The security of communications with a partner service, on the other hand, is dependent on the effectiveness of that service's security procedures. Containers may wish to rate limit requests from unknown clients, or require registration, in order to mitigate risk. Containers should scope oauth_tokens as narrowly as possible (e.g., allow reading but not writing if a client only performs reads). 8. Concurrency Control (Optional)This feature allows a container and client to cooperate in order to prevent multiple containers from overwriting each other's data. It uses the standard HTTP/AtomPub optimistic concurrency mechanism based on ETags (see section 9.5 of [RFC5023] for details; the same mechanism applies regardless of the data format used for the body of the PUT). 8.1 DiscoveryConcurrency control is available on a resource-by-resource basis. When an updateable resource supports concurrency control, the container SHOULD supply an ETag encoding the resource's current state when supplying a representation to clients. If a resource does not support optimistic concurrency, it MUST respond to an update request containing an If-Match: header with a 403 Not Implemented error. A server which chooses not to support optimistic concurrency SHOULD omit ETags on its responses for updateable resources. A client SHOULD assume that optimistic concurrency is not available if no ETag is present. 8.2 SemanticsWhen a client is given an ETag, it MAY supply that ETag in an If-Match: header on subsequent updates. The semantics are that the client can supply the new representation and the previous ETag; the server inspects the current state of the resource and applies the update if the client supplied ETag matches (meaning no intervening updates have happened), otherwise responds with a 409 Conflict error and the new ETag. Clients may then take appropriate actions to resolve the conflict, or fail the operation, depending on their needs. Clients are also free to use PUT to simply overwrite a resource with a new state at any time, ignoring possible overwriting problems. If partial updates are supported (see below), a server MUST accept an ETag given for either a base resource or a projection of that resource upon a subsequent PUT for that resource. That is, it is legal to supply an ETag you received when GETting the full representation of a resource even if you are only PUTting back a single field. If you intend to simply overwrite that single field, then you skip sending any ETag. 9. Batching (Optional)There are use cases where clients want to send several operations, in a specified sequence, to a server to execute in turn, but do not want to incur the overhead of multiple HTTP round trips. A specific use case is a gadget which first adds a new friend, then retrieves the 5th page of friends (what it's currently viewing). These are two ad hoc requests from the point of view of the server involved, but for optimization purposes the gadget wants to batch up the requests and responses to minimize latency. It is also possible that the requests and responses would be to different types of data (activities, people, or persistence) and/or to different servers. In the most general case it is useful to be able to batch any type of request, including requests to third party servers (e.g., "phone home" requests) that need to be executed in sequence with container-local requests; in this case the container API is acting as a proxy (and should take appropriate security precautions to avoid abuse). This optional feature allows a container to accept an arbitrary sequence of operations while using only one HTTP round trip between server and client for the overall set of requests and response. 9.1 DiscoveryIf a container supports batching, it advertises a "batch-proxy" Service in its discovery document: <Service> The method may be either POST or BATCH. Containers SHOULD support the BATCH method if possible, but MUST support the POST method. Clients SHOULD support the BATCH method but MUST be able to fall back to the POST method. 9.2 SemanticsThe semantics of a set of batched requests in this proposal are exactly the same as sending the same requests individually. In particular, the server does not provide any atomicity guarantees. The server is not allowed to reorder or parallelize the requests unless it can do so without client-visible side effects. The simplest server implementation is to loop over the requests, executing each in turn, and appending responses into a batch response to send to the client. The batch interface is an optional part of OpenSocial. If a server does not support it, a client falls back to using individual requests and responses with no changes in semantics. Depending on the exact situation, it may be more efficient to use individual requests which can be parallelized and cached, or to use batch serial requests; a goal with this API is to make it simple for a client to switch between the two mechanisms and to keep the semantics consistent and straightforward. To this end, a batch request is represented by an envelope HTTP request sent to a batching proxy resource. The client POSTs the document described below to the proxy URI, which returns 200 OK when the contents have been processed (successfully or not) and returns a response sequence document. Both request and response sequence documents are represented by standard multipart/mixed documents; the individual requests and responses are represented by standard application/http;version=1.1 documents (see RFC2616, section 19.1). These documents encapsulate what would be sent over the wire for a standard, stand-alone HTTP request. An example request with two parts: POST /batch-proxy HTTP/1.1 The response: HTTP/1.1 200 OK In this case, the friend add succeeded and the response to the retrieval of page 5 of the friends list indicates that page 5 didn't change (the friend was added below that page's last entry). If the resource had changed, of course, there would be a list of the friends in the response. Only the top level request can specify overall request related things such as keepalives and content transfer encoding. The top level request response code is:
Individual responses use the HTTP response codes they would have used had they been executed individually. Requests and responses are matched by position, and the server guarantees that if it sends back a response, the nth response is for the nth request. It does not guarantee that the number of responses matches the number of requests; in particular, network problems might truncate a response document or drop a connection, and in this case clients are left not knowing the status of the remaining responses. If a server needs to indicate that a particular sub-request timed out without any indication of whether it succeeded or failed, it should use "X-Batch-Status: 504 Gateway Timeout" to indicate that it has a known unknown. Clients seeing a 504 sub-response should be advised that the request may have completed before timing out. Note that a container MAY support proxying to foreign servers (via the Host: header); however, servers are not required to support this and clients SHOULD NOT assume the capability. In general, HTTP fields may be added to either the envelope request or sub-requests. For example, a client may add an Authorization: header to the envelope request (to authorize itself to the proxy service) and also add Authorization: header(s) to different sub-requests (to authorize itself to other services). (This extension generally follows the proposal at http://www.snellspace.com/wp/?p=886, which is also the semantics used by Astoria.) 10. Partial Updates (Optional)Partial updates avoid the need to send full representations of data on updates, especially for People and App Data. The primary use case is when a client has retrieved a full representation and subsequently wishes to send a small update to a server. In the most general case, the client my have a series of small updates (e.g., changing tags on a large number of contacts) scattered across many resources. It should also allow for concurrency control. We wish to have a generalized partial update / patching mechanism to handle such cases. As with the batching mechanism, it should be optional on the server side; clients can always fall back to sending full representations back to the server if it does not support the mechanism. The exact syntax is TBD at this point. 11. Messaging (Optional)A social network service may optionally expose a mechanism for sending short messages between users. The functionality and policies are parallel to those of the JS API's requestSendMessage. DiscoveryIf a container supports messaging, it advertises a "messages" Service in its discovery document: <Service> SemanticsTo create a message and place it in a queue, a client PUTs a message to an 'outbox' collection resource discovered from the XRDS document: PUT /messages/{guid}/outbox/{msgid}
The outbox is owned by the source user. Placing a message in the outbox requests that the message be delivered to one or more recipients. Containers are free to filter or alter the message according to their own policies (such as security or rate limiting policies). The format of the message is the same as an activity, but with an additional set of recipients (osapi:recipient): <entry xmlns="http://www.w3.org/2005/Atom" The {msgid} is client generated and SHOULD be globally unique. If a client does not care about failure cases, it can alternatively use a standard AtomPub POST to /messages/{source-uid}/outbox and leave generation of the ID to the container. In either case, the response is 201 Created on success. If not supported, the response code should be 403 Not Implemented. Typically a container would choose to only allow a PUT to an outbox where the {guid} equals the requestor id, but this is a container security policy decision. Containers may choose to allow messaging only between friends or user other heuristics to prevent spam. The copyrights in this specification are licensed under the Creative Commons Attribution 2.5 license | Terms of Service |