JMAP for Calendars is awesome
The old thing: CalDAV
The predominant protocol used for syncing calendars is CalDAV (RFC 4791). CalDAV is a weird protocol. It sends events in the iCalendar format (RFC 5545) over WebDAV (RFC 4918), which in turn is based on XML and a modified version of HTTP. This is one example from the spec:
>> Request <<
REPORT /bernard/work/ HTTP/1.1
Host: cal.example.com
Depth: 1
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop>
<C:calendar-data>
<C:limit-freebusy-set start="20060102T000000Z" end="20060103T000000Z"/>
</C:calendar-data>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VFREEBUSY">
<C:time-range start="20060102T000000Z" end="20060103T000000Z"/>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
>> Response <<
HTTP/1.1 207 Multi-Status
Date: Sat, 11 Nov 2006 09:32:12 GMT
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd8.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd8"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VFREEBUSY
ORGANIZER;CN="Bernard Desruisseaux":mailto:bernard@example.com
UID:76ef34-54a3d2@example.com
DTSTAMP:20050530T123421Z
DTSTART:20060101T100000Z
DTEND:20060108T100000Z
FREEBUSY;FBTYPE=BUSY-TENTATIVE:20060102T100000Z/20060102T120000Z
END:VFREEBUSY
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
Note how this uses the REPORT
method, which is not part of stock HTTP. Also, note how iCalendar is embedded in XML. It is certainly not impossible to parse this, but it is far more complicated than it should be.
The biggest issue with CalDAV is that it is not universally supported. For example, FullCalendar, the go-to JavaScript calendar, does not support CalDAV on its own. Since version 5.5 it does at least allow to subscribe to read-only iCalendar feeds over HTTP though. Microsoft products do the same. If you want to get proper read-write support to your Microsoft calendars, you have to use their proprietary Exchange ActiveSync protocol.
I have recently worked with CalDAV and encountered two other issues:
The events I worked with were all associated with an URL. iCalendar does not offer an URL field, so users had to open the event, copy the URL from the description field, and manually enter it into their browsers. This is not a huge issue. Still, I believe this use case is common enough to warrant a smoother user experience.
There is no way for the server to notify clients of changes. Clients typically poll for new events in regular intervals. This means that users might make appointments in slots that are already taken because they work with outdated data.
Frustrated with all those issues, I started thinking about a new protocol that could replace CalDAV. After a bit of research, I found that someone had already done that work.
The new thing: JMAP Calendars
JMAP Calendars is a draft spec to send events in JSCalendar format (RFC 8984) over JMAP (RFC 8620), which in turn is an RPC protocol based on HTTP and JSON. Here is an example request from the spec:
[
["CalendarEvent/set", {
"accountId": "a0x9",
"create": {
"k559": {
"uid": "5d5776f6-ff8e-4bfd-ab3e-fe2fe5d4fa91",
"calendarIds": {
"3ddf2ad7-0e0c-4fb5-852d-f0ff56f3c662": true
},
"title": "Party at Pete’s",
"start": "2023-02-03T19:00:00",
"duration": "PT3H0M0S",
"timeZone": "Australia/Melbourne",
"showWithoutTime": false,
"participants": {
"1": {
"@type": "Participant",
"name": "Jane Doe"
"scheduleId": "mailto:jane@example.com",
"sendTo": {
"imip": "mailto:jane@example.com",
"other": "https://example.com/uri/for/internal/scheduling"
}
"kind": "individual",
"roles": {
"attendee": true,
"owner": true
},
"participationStatus": "accepted",
"expectReply": false
},
"2": {
"@type": "Participant",
"name": "Joe Bloggs",
"sendTo": {
"imip": "mailto:joe@example.com"
},
"kind": "individual",
"roles": {
"attendee": true
},
"participationStatus": "needs-action",
"expectReply": true
}
},
"mayInviteSelf": false,
"mayInviteOthers": false,
"useDefaultAlerts": false,
"alerts": null
}
},
"sendSchedulingMessages": true
}, "0"]
]
This solves most of CalDAV problems:
- It is a much cleaner protocol. JMAP and JSCalendar both use JSON, so parsing is simple. JMAP uses stock HTTP. I would have preferred it to be more REST and less RPC, but that is something I can happily live with.
- JSCalendar is based on the semantics of iCalendar, but also makes some updates. For example, it adds a
Links
field and even avirtualLocations
field for online meetings. - JMAP has push support either via Server-sent events or external push services.
Of course, support for JMAP Calendars is currently even worse than it is for CalDAV. To my knowledge, JMAP Calendars is not supported anywhere yet, and JMAP in general hasn't seen much adoption either.
On the other hand, HTTP and JSON are the de-facto standard for building APIs on the web. With this clean protocol based on popular technologies, there is hope that developers will add support once the spec stabilizes. I at least hope to see a switch from iCalendar-over-HTTP to JSCalendar-over-HTTP.
There are some other protocols (e.g. LDAP) that I would like to see replaced by something based on HTTP and JSON. There are certainly many pros and cons to this idea, not least of which is the difficulty for new protocols to gain traction. Maybe JMAP Calendars can serve as a test to see if this is worth the effort.