Tomboy Web, A RESTful API for Tomboy Note Synchronization

DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT

Things I'd like to add in 1.1:

  • Maybe: have an /api/ endpoint that is guaranteed to contain at least api-version, so clients don't have to hit /api/1.2/, /api/1.1/, then /api/1.0/ to figure out that some server only supports 1.0.
  • DEFINITELY add current-sync-guid to all note endpoints (maybe all endpoints, period?). Stupid to assume this can't change between hitting /api/1.1/user/ and /api/1.1/user/notes/.
  • I'd also like to add an include_notes_since parameter to the notes endpoint. This would get all notes, but only include content since the specified version. This cuts down the number of API calls required to do a sync by one, because clients need a complete list of GUIDs to detect server-side note deletion.

  • I don't like include_notes or include_notes_since names. Why not include_content as an alias for include_notes, and include_content_since as an alias for include_notes_since? Then again, include_notes brings more than just content, it brings timestamps/etc.

  • Would it be worthwhile to have API that lets clients specify the exact fields they care about, instead of only being able to toggle content?
  • Add a recommendation that clients cache the URL of the notes API endpoint, and only go through the root->user->notes process when that URL errors-out. This is just a hack to reduce server requests.

  • Clarify policy on trailing / ?
  • Maybe: a boolean encrypted property on Note objects. We definitely need to support encrypted note storage, and a flag like this would save us the time of trying and failing to parse/transform it. A good question is what this flag specifies to be encrypted. Do we encrypt titles and tags? I'd rather start with the simple and easy-to-implement support for encrypted content. Encrypting titles and tags may be desired, but could break things a lot more interestingly.

  • Stricter guid format. Currently, guid has no rules at all except uniqueness. For the sake of DB-based Tomboy clients, should probably say it's a string with a 36 char max length. Still will not require that it is a properly-formatted UUID. This would require changes in Tomboy.

DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT

This is the documentation of the 1.1 version of the REST API used by Tomboy, Tomdroid, and Conboy to perform web synchronization with Snowy, Ubuntu One, and Midgard2. Improvements are expected in future versions, but since a Tomboy Web sync add-in shipped in Tomboy 1.0, any updates must keep backwards compatibility in mind.

(A note about REST: As Tomboy notes are interconnected, CRUD of individual note resources has a lot of implications and is not initially supported. The method for updating notes on the server breaks a few REST principles, but is still pretty clean.)

Tomboy's synchronization algorithm is in the process of being documented.

Resources

Responses should be returned in JSON format, as shown in the examples below.

Current spec requires use of OAuth 1.0 or 1.0a for authentication.

URIs include "api" , so that you can, for example, visit http://domain/sally/notes/123/new-note-6 and get a pretty interactive web page, then visit http://domain/api/1.1/sally/notes/123 to get the JSON/XML/whatever response.

Another very important note about these URLs: although the spec refers to URLs like api/1.1/user/notes, this exact URL is not required. The only exact URL that is required is api/1.1. When authenticated, that URL will provide a user-ref containing another API URL (which may or may not be api/1.1/user), and the user URL will provide a notes-ref containing yet another API URL (which may or may not be api/1.1/user/notes). Clients of this API must take this into account when developing support for this REST API. Of note, Ubuntu One does not use the exact URLs listed here for users and notes.

http://domain/api/1.1

{
        "user-ref": {
                "api-ref" : "http://domain/api/1.1/sally",
                "href" : "http://domain/sally"
        },
        "oauth_request_token_url": "http://domain/oauth/request_token",
        "oauth_authorize_url": "http://domain/oauth/authorize",
        "oauth_access_token_url": "http://domain/oauth/access_token",
        "api-version": "1.1"
}

http://domain/api/1.1/user

{
        "user-name": "sally",
        "first-name": "sally",
        "last-name": "walters",
        "notes-ref": {
                "api-ref" : "http://domain/api/1.1/sally/notes",
                "href" : "http://domain/sally/notes"
        },
        "latest-sync-revision": 456   (maybe you only get this number if the user is you?),
        "current-sync-guid": "ff2e91b2-1234-4eab-3000-abcde49a7705"   (maybe you only get this number if the user is you?)
}

http://domain/api/1.1/user/notes

  • Supported HTTP Methods: GET, PUT
    • A PUT lets you update/add/delete notes in the collection
  • Supported query parameters:
    • since - an integer specifying a sync revision number

    • include_notes - a boolean defaulting to False indicating whether or not full note data should be included (I wish I had called this include_content instead. Maybe in a future update to this API we will add include_content as an alias for include_notes, and recommend it instead for clarity)

    • content_version - ability for for clients to request note content in older versions or different formats (such as markdown)

  • Response example: GET http://domain/api/1.1/sally/notes

{
        "latest-sync-revision": 456,
        "notes": [{
                        "guid": "002e91a2-2e34-4e2d-bf88-21def49a7705",
                        "ref": {
                                "api-ref": "http://domain/api/1.1/sally/notes/123",
                                "href": "http://domain/sally/notes/123/new-note-6"
                        },
                        "title": "New Note 6"
                }, {
                        ...(another one)...
                }]
}

{
        "latest-sync-revision": 456,
        "notes": [{
                        "guid": "002e91a2-2e34-4e2d-bf88-21def49a7705",
                        "title": "New Note 6",
                        "note-content": "Describe your note <b>here</b>.",
                        "note-content-version": 0.1,
                        "last-change-date": "2009-04-19T21:29:23.2197340-07:00",
                        "last-metadata-change-date": "2009-04-19T21:29:23.2197340-07:00",
                        "create-date": "2008-03-06T13:44:46.4342680-08:00",
                        "last-sync-revision": 57,
                        "open-on-startup": false,
                        "pinned": false,
                        "tags": ["tag1", "tag2", "tag3", "system:notebook:biology"]
                }, {
                        ...(another one)...
                }]
}

{
        "latest-sync-revision": 456,
        "note-changes": [{
                        "guid": "002e91a2-2e34-4e2d-bf88-21def49a7705",
                        "title": "New Note 6",
                        "note-content": "Describe your note <b>here</b>.",
                        "note-content-version": 0.1,
                        "last-change-date": "2009-04-19T21:29:23.2197340-07:00",
                        "last-metadata-change-date": "2009-04-19T21:29:23.2197340-07:00",
                        "create-date": "2008-03-06T13:44:46.4342680-08:00",
                        "open-on-startup": false,
                        "pinned": false,
                        "tags": ["tag1", "tag2", "tag3", "system:notebook:biology"]
                }, {
                        ...(another one)...
                }, {
                        "guid": "0bc7b1ef-264f-4aa9-8746-d0f87e9b0176",
                        "command": "delete"
                }]                      
}

http://domain/api/1.1/user/notes/id

  • Supported HTTP Methods: GET
  • Supported query parameters:
  • Not required for sync
  • Response example: GET http://domain/api/1.1/sally/notes/123 (Consider dropping "note", also redundant array notation)

{
        "note": [{
                        "guid": "002e91a2-2e34-4e2d-bf88-21def49a7705",
                        "title": "New Note 6",
                        "note-content": "Describe your note <b>here</b>.",
                        "note-content-version": 0.1,
                        "last-change-date": "2009-04-19T21:29:23.2197340-07:00",
                        "last-metadata-change-date": "2009-04-19T21:29:23.2197340-07:00",
                        "create-date": "2008-03-06T13:44:46.4342680-08:00",
                        "open-on-startup": false,
                        "pinned": false,
                        "tags": ["tag1", "tag2", "tag3", "system:notebook:biology"]
                }]
}

Things to Consider When PUT/POSTing Resources

Notes

All fields of a Note object are optional, except the GUID (which need only be a unique string of any length). Let's explore the consequences of setting or not setting Note object fields:

Field

If Included

If Excluded

guid

Required

Required

ref

Ignored on PUT/POST

Ignored

title

Updated

Ignored

note-content

Updated

Ignored

note-content-version

Updated

Required with note-content, or default to 0.1?

last-change-date

Updated

Ignored (though maybe it should be updated to current datetimestamp if title or content are modified?)

last-metadata-change-date

Updated

Updated to current datetimestamp

create-date

Updated

Ignored

open-on-startup

Updated

Ignored

pinned

Updated

Ignored

tags

Updated (previous tags overwritten with newly-specified tags)

Ignored

command

If set to 'delete', note will be deleted; otherwise, ignored

Ignored

Apps/Tomboy/Synchronization/REST/1.1 (last edited 2013-08-09 00:14:59 by WilliamJonMcCann)