idnits 2.17.1 draft-ietf-jmap-core-06.txt: Checking boilerplate required by RFC 5378 and the IETF Trust (see https://trustee.ietf.org/license-info): ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/1id-guidelines.txt: ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/checklist : ---------------------------------------------------------------------------- ** There are 2 instances of too long lines in the document, the longest one being 34 characters in excess of 72. Miscellaneous warnings: ---------------------------------------------------------------------------- == The copyright year in the IETF Trust and authors Copyright Line does not match the current year -- The document date (July 2, 2018) is 2118 days in the past. Is this intentional? -- Found something which looks like a code comment -- if you have code sections in the document, please surround them with '' and '' lines. Checking references for intended status: Proposed Standard ---------------------------------------------------------------------------- (See RFCs 3967 and 4897 for information about using normative references to lower-maturity documents in RFCs) -- Looks like a reference, but probably isn't: '1' on line 2519 ** Obsolete normative reference: RFC 5246 (Obsoleted by RFC 8446) ** Obsolete normative reference: RFC 5785 (Obsoleted by RFC 8615) ** Obsolete normative reference: RFC 7159 (Obsoleted by RFC 8259) ** Obsolete normative reference: RFC 7230 (Obsoleted by RFC 9110, RFC 9112) ** Obsolete normative reference: RFC 7235 (Obsoleted by RFC 9110) ** Obsolete normative reference: RFC 7807 (Obsoleted by RFC 9457) Summary: 7 errors (**), 0 flaws (~~), 1 warning (==), 3 comments (--). Run idnits with the --verbose option for more detailed information about the items above. -------------------------------------------------------------------------------- 2 JMAP N. Jenkins 3 Internet-Draft FastMail 4 Intended status: Standards Track July 2, 2018 5 Expires: January 3, 2019 7 JSON Meta Application Protocol 8 draft-ietf-jmap-core-06 10 Abstract 12 This document specifies a protocol for synchronising JSON-based data 13 objects efficiently, with support for push and out-of-band binary 14 data upload/download. 16 Status of This Memo 18 This Internet-Draft is submitted in full conformance with the 19 provisions of BCP 78 and BCP 79. 21 Internet-Drafts are working documents of the Internet Engineering 22 Task Force (IETF). Note that other groups may also distribute 23 working documents as Internet-Drafts. The list of current Internet- 24 Drafts is at https://datatracker.ietf.org/drafts/current/. 26 Internet-Drafts are draft documents valid for a maximum of six months 27 and may be updated, replaced, or obsoleted by other documents at any 28 time. It is inappropriate to use Internet-Drafts as reference 29 material or to cite them other than as "work in progress." 31 This Internet-Draft will expire on January 3, 2019. 33 Copyright Notice 35 Copyright (c) 2018 IETF Trust and the persons identified as the 36 document authors. All rights reserved. 38 This document is subject to BCP 78 and the IETF Trust's Legal 39 Provisions Relating to IETF Documents 40 (https://trustee.ietf.org/license-info) in effect on the date of 41 publication of this document. Please review these documents 42 carefully, as they describe your rights and restrictions with respect 43 to this document. Code Components extracted from this document must 44 include Simplified BSD License text as described in Section 4.e of 45 the Trust Legal Provisions and are provided without warranty as 46 described in the Simplified BSD License. 48 Table of Contents 50 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 51 1.1. Notational conventions . . . . . . . . . . . . . . . . . 4 52 1.2. The Number data type . . . . . . . . . . . . . . . . . . 4 53 1.3. The Date data types . . . . . . . . . . . . . . . . . . . 4 54 1.4. JSON as the data encoding format . . . . . . . . . . . . 5 55 1.5. Terminology . . . . . . . . . . . . . . . . . . . . . . . 5 56 1.5.1. User . . . . . . . . . . . . . . . . . . . . . . . . 5 57 1.5.2. Accounts . . . . . . . . . . . . . . . . . . . . . . 5 58 1.5.3. Data types and records . . . . . . . . . . . . . . . 5 59 1.6. Ids . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 60 1.7. The JMAP API model . . . . . . . . . . . . . . . . . . . 6 61 2. The JMAP Session resource . . . . . . . . . . . . . . . . . . 7 62 2.1. Example . . . . . . . . . . . . . . . . . . . . . . . . . 10 63 2.2. Service Autodiscovery . . . . . . . . . . . . . . . . . . 12 64 3. Structured data exchange . . . . . . . . . . . . . . . . . . 12 65 3.1. Making an API request . . . . . . . . . . . . . . . . . . 12 66 3.2. The Request object . . . . . . . . . . . . . . . . . . . 12 67 3.2.1. Example request . . . . . . . . . . . . . . . . . . . 14 68 3.3. Vendor-specific extensions . . . . . . . . . . . . . . . 14 69 3.4. The Response object . . . . . . . . . . . . . . . . . . . 14 70 3.4.1. Example response: . . . . . . . . . . . . . . . . . . 15 71 3.5. Omitting arguments . . . . . . . . . . . . . . . . . . . 15 72 3.6. Errors . . . . . . . . . . . . . . . . . . . . . . . . . 15 73 3.6.1. Error responses . . . . . . . . . . . . . . . . . . . 15 74 3.6.2. Method-level errors . . . . . . . . . . . . . . . . . 16 75 3.7. References to previous method results . . . . . . . . . . 17 76 3.8. Security . . . . . . . . . . . . . . . . . . . . . . . . 22 77 3.9. Concurrency . . . . . . . . . . . . . . . . . . . . . . . 22 78 4. Standard methods and naming convention . . . . . . . . . . . 22 79 4.1. /get . . . . . . . . . . . . . . . . . . . . . . . . . . 22 80 4.2. /changes . . . . . . . . . . . . . . . . . . . . . . . . 24 81 4.3. /set . . . . . . . . . . . . . . . . . . . . . . . . . . 25 82 4.4. /query . . . . . . . . . . . . . . . . . . . . . . . . . 30 83 4.5. /queryChanges . . . . . . . . . . . . . . . . . . . . . . 34 84 4.6. Examples . . . . . . . . . . . . . . . . . . . . . . . . 37 85 5. Binary data . . . . . . . . . . . . . . . . . . . . . . . . . 41 86 5.1. Uploading binary data . . . . . . . . . . . . . . . . . . 42 87 5.2. Downloading binary data . . . . . . . . . . . . . . . . . 43 88 5.3. Blob/copy . . . . . . . . . . . . . . . . . . . . . . . . 44 89 6. Push . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 90 6.1. The StateChange object . . . . . . . . . . . . . . . . . 45 91 6.2. PushSubscription . . . . . . . . . . . . . . . . . . . . 45 92 6.2.1. PushSubscription/set . . . . . . . . . . . . . . . . 47 93 6.2.2. PushSubscription/get . . . . . . . . . . . . . . . . 47 94 6.3. Event Source . . . . . . . . . . . . . . . . . . . . . . 47 95 7. Security considerations . . . . . . . . . . . . . . . . . . . 49 96 7.1. Transport confidentiality . . . . . . . . . . . . . . . . 49 97 7.2. Authentication scheme . . . . . . . . . . . . . . . . . . 49 98 7.3. Service autodiscovery . . . . . . . . . . . . . . . . . . 49 99 7.4. JSON parsing . . . . . . . . . . . . . . . . . . . . . . 49 100 7.5. Denial of service . . . . . . . . . . . . . . . . . . . . 50 101 7.6. Push encryption . . . . . . . . . . . . . . . . . . . . . 50 102 8. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 50 103 8.1. Assignment of jmap Service Name . . . . . . . . . . . . . 50 104 8.2. Registration of Well-known URI suffix for JMAP . . . . . 51 105 8.3. Registration of the jmap URN Sub-namespace . . . . . . . 51 106 8.4. Creation of "JMAP capabilities" registry . . . . . . . . 51 107 8.4.1. Preliminary Community Review . . . . . . . . . . . . 52 108 8.4.2. Submit Request to IANA . . . . . . . . . . . . . . . 52 109 8.4.3. Designated Expert Review . . . . . . . . . . . . . . 52 110 8.4.4. Change Procedures . . . . . . . . . . . . . . . . . . 52 111 8.4.5. JMAP Capabilities Registry Template: . . . . . . . . 53 112 8.4.6. Initial Registration . . . . . . . . . . . . . . . . 53 113 9. References . . . . . . . . . . . . . . . . . . . . . . . . . 53 114 9.1. Normative References . . . . . . . . . . . . . . . . . . 54 115 9.2. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 56 116 Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 56 118 1. Introduction 120 JMAP is a generic protocol for synchronising data, such as mail, 121 calendars or contacts, between a client and a server. It is 122 optimised for mobile and web environments, and aims to provide a 123 consistent interface to different data types. 125 This specification is for the generic mechanism of data 126 synchronisation. Further specifications define the data models for 127 different data types that may be synchronised via JMAP. 129 JMAP is designed to make efficient use of limited network resources. 130 Multiple API calls may be batched in a single request to the server, 131 reducing round trips and improving battery life on mobile devices. 132 Push connections remove the need for polling, and an efficient delta 133 update mechanism ensures a minimum of data is transferred. 135 JMAP is designed to be horizontally scalable to a very large number 136 of users. This is facilitated by the separate end points for users 137 after login, the separation of binary and structured data, and a 138 shared data model that does not allow data dependencies between 139 accounts. 141 1.1. Notational conventions 143 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 144 "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 145 document are to be interpreted as described in [RFC2119]. 147 The underlying format used for this specification is JSON. 148 Consequently, the terms "object" and "array" as well as the four 149 primitive types (strings, numbers, booleans, and null) are to be 150 interpreted as described in Section 1 of [RFC7159]. Unless otherwise 151 noted, all the property names and values are case sensitive. 153 Some examples in this document contain "partial" JSON documents used 154 for illustrative purposes. In these examples, three periods "..." 155 are used to indicate a portion of the document that has been removed 156 for compactness. 158 Type signatures are given for all JSON objects in this document. The 159 following conventions are used: 161 o "Boolean|String" - The value is either a JSON "Boolean" value, or 162 a JSON "String" value. 164 o "Foo" - Any name that is not a native JSON type means an object 165 for which the properties (and their types) are defined elsewhere 166 within this document. 168 o "Foo[]" - An array of objects of type "Foo". 170 o "String[Foo]" - A JSON "Object" being used as a map (associative 171 array), where all the values are of type "Foo". 173 1.2. The Number data type 175 The JSON data types are limited to those found in JavaScript. A 176 "Number" in JavaScript is represented as a signed double (64-bit 177 floating point). However, except where explicitly specified, all 178 numbers used in this API are unsigned integers <= 2^53 (the maximum 179 integer that may be reliably stored in a double). 181 1.3. The Date data types 183 Where "Date" is given as a type, it means a string in [RFC3339] 184 _date-time_ format. To ensure a normalised form, the _time-secfrac_ 185 MUST always be omitted and any letters in the string (e.g. "T" and 186 "Z") MUST be upper-case. For example, ""2014-10-30T14:12:00+08:00"". 188 Where "UTCDate" is given as a type, it means a "Date" where the 189 _time-offset_ component MUST be "Z" (i.e. it must be in UTC time). 190 For example, ""2014-10-30T06:12:00Z"". 192 1.4. JSON as the data encoding format 194 JSON is a text-based data interchange format as specified in 195 [RFC7159]. The I-JSON format defined in [RFC7493] is a strict subset 196 of this, adding restrictions to avoid potentially confusing scenarios 197 (for example, it mandates that an object MUST NOT have two properties 198 with the same key). 200 All data sent from the client to the server or from the server to the 201 client (except binary file upload/download) MUST be valid I-JSON 202 according to the RFC, and is therefore case-sensitive and encoded in 203 UTF-8 ([RFC3629]). 205 1.5. Terminology 207 1.5.1. User 209 A user represents a set of permissions relating to what data can be 210 seen. 212 1.5.2. Accounts 214 An account is a collection of data. A single account may contain an 215 arbitrary set of data types, for example a collection of mail, 216 contacts and calendars. Most operations in JMAP are isolated to a 217 single account; there are a few explicit operations to copy data 218 between them. Certain properties are guaranteed for data within the 219 same account, for example uniqueness of ids within a type in that 220 account. 222 An account is not the same as a user, although it is common for a 223 primary account to directly belong to the user. For example, you may 224 have an account that contains data for a group or business, to which 225 multiple users have access. Users may also have access to accounts 226 belonging to another user if that user is sharing some of their data. 227 A single set of credentials may provide access to data in multiple 228 accounts. 230 1.5.3. Data types and records 232 JMAP provides a uniform interface for creating, retrieving, updating 233 and deleting various types of objects. A *data type* is a collection 234 of named, typed properties, just like the schema for a database 235 table. Each instance of a data type is called a *record*. 237 1.6. Ids 239 All record ids are assigned by the server, and are immutable. They 240 MUST be unique among all records of the *same type* within the *same 241 account*. Ids may clash across accounts, or for two records of 242 different types within the same account. 244 Ids are always "String"s. An id MUST be at least 1 character in 245 length and maximum 255 octets in size, and MUST only contain 246 characters from the "URL and Filename safe" Base 64 Alphabet, as 247 defined in section 5 of [RFC4648]. This is the ASCII alphanumeric 248 characters ("A-Za-z0-9"), hyphen ("-"), and underscore ("_"). 250 1.7. The JMAP API model 252 JMAP uses HTTP [RFC7230] to expose API, Push, Upload and Download 253 resources. Implementations MUST support HTTP/1.1, and MAY support 254 later versions. Support for common HTTP mechanisms such as 255 redirection and caching are assumed. 257 All HTTP requests MUST be authenticated. Servers MUST conform with 258 the [RFC7235] HTTP Authentication framework to reject requests that 259 fail authentication and inform the client of available authentication 260 schemes. 262 Clients SHOULD understand and be able to handle standard HTTP status 263 codes appropriately. 265 An authenticated client can fetch the JMAP Session object with 266 details about the data and capabilities the server can provide as 267 shown in section 2. The client may then exchange data with the 268 server in the following ways: 270 1. The client may make an API request to the server to get or set 271 structured data. This request consists of an ordered series of 272 method calls. These are processed by the server, which then 273 returns an ordered series of responses. This is described in 274 sections 3 and 4. 276 2. The client may download or upload binary files from/to the 277 server. This is detailed in section 5. 279 3. The client may connect to a push channel on the server, to be 280 notified when data has changed. This is explained in section 6. 282 2. The JMAP Session resource 284 You need two things to connect to a JMAP server: 286 1. The URL for the JMAP Session resource. This may be requested 287 directly from the user, or discovered automatically based on a 288 username domain (see Service Autodiscovery section below). 290 2. Credentials to authenticate with. How to obtain credentials is 291 out of scope for this specification. 293 An authenticated GET request to the JMAP Session resource MUST return 294 the details about the data and capabilities the server can provide to 295 the client given those credentials. 297 The response to a successful request is a JSON-encoded *JMAP Session* 298 object. It has the following properties: 300 o *username*: "String" The username associated with the given 301 credentials. 303 o *accounts*: "String[Account]" A map of *account id* to Account 304 object for each account the user has access to. A single set of 305 credentials may provide access to multiple accounts, for example 306 if another user is sharing their mail with the logged in user, or 307 if there is an account that contains data for a group or business. 308 All data belongs to a single account. With the exception of a few 309 explicit operations to copy data between accounts, all JMAP 310 methods take an _accountId_ argument that specifies on which 311 account the operations are to take place. This argument is always 312 optional; if not specified, the primary account for the capability 313 that defines the data type is used. (Though if there is no 314 primary account for that capability, an "accountNotFound" error 315 will be returned.) All ids (other than account ids, of course) 316 are only unique within their account. In the event of a severe 317 internal error, a server may have to reallocate ids or do 318 something else that violates standard JMAP data constraints. In 319 this situation, the data on the server is no longer compatible 320 with cached data the client may have from before. The server MUST 321 treat this as though the account has been deleted and then 322 recreated with a new account id. Clients will then be forced to 323 throw away any data with the old account id and refetch all data 324 from scratch. An *Account* object has the following properties: 326 * *name*: "String" A user-friendly string to show when presenting 327 content from this account, e.g. the email address representing 328 the owner of the account. 330 * *isReadOnly*: "Boolean" This is "true" if the entire account is 331 read-only. 333 * *hasDataFor*: "String[]" A list of specification URIs for the 334 object types supported in this account. The server advertises 335 the list of specifications it supports in general in the 336 capabilities object, as defined below. If the specification 337 includes new object type definitions, the server MUST include 338 it the _hasDataFor_ array if, and only if, the user may use 339 those data types with this account. For example, you may have 340 access to your own account with mail, calendars and contacts 341 data, and also a shared account that only has contacts data (a 342 business address book for example). In this case the 343 _hasDataFor_ property on the first account would include 344 something like "urn:ietf:params:jmap:mail", 345 "urn:ietf:params:jmap:calendars", 346 "urn:ietf:params:jmap:contacts", while the second account would 347 just have the last of these. Attempts to use the methods 348 defined in a specification with one of the accounts that does 349 not contain those data types are rejected with an 350 _accountNotSupportedByMethod_ error (see the Method-level 351 errors section below). 353 o *primaryAccounts*: "String[String]" A map of capability URIs (as 354 found in _hasDataFor_) to the account id to be considered the 355 user's main or default account for data pertaining to that 356 capability. If no account being returned belongs to the user, or 357 in any other way there is no appropriate way to determine a 358 default account, there MAY be no entry for a particular data 359 profile name. "urn:ietf:params:jmap:core" SHOULD NOT be present. 361 o *capabilities*: "String[Object]" An object specifying the 362 capabilities of this server. Each key is a URI for a 363 specification supported by the server. The value for each of 364 these keys is an object with further information about the 365 server's capabilities in relation to that specification. The 366 client MUST ignore any properties it does not understand. The 367 capabilities object MUST include a property called 368 "urn:ietf:params:jmap:core". The value of this property is an 369 object which MUST contain the following information on server 370 capabilities: 372 * *maxSizeUpload*: "Number" The maximum file size, in octets, 373 that the server will accept for a single file upload (for any 374 purpose). 376 * *maxConcurrentUpload*: "Number" The maximum number of 377 concurrent requests the server will accept to the upload 378 endpoint. 380 * *maxSizeRequest*: "Number" The maximum size, in octets, that 381 the server will accept for a single request to the API 382 endpoint. 384 * *maxConcurrentRequests*: "Number" The maximum number of 385 concurrent requests the server will accept to the API endpoint. 387 * *maxCallsInRequest*: "Number" The maximum number of method 388 calls the server will accept in a single request to the API 389 endpoint. This MUST be greater than or equal to "32" to ensure 390 clients can rely on the ability to make efficient network use. 392 * *maxObjectsInGet*: "Number" The maximum number of objects that 393 the client may request in a single "/get" type method call. 395 * *maxObjectsInSet*: "Number" The maximum number of objects the 396 client may send to create, update or destroy in a single "/set" 397 type method call. 399 * *collationAlgorithms*: "String[]" A list of identifiers for 400 algorithms registered in the collation registry defined in 401 [RFC4790] that the server supports for sorting when querying 402 records. 404 Future specifications will define their own properties on the 405 capabilities object. Servers MAY advertise vendor-specific JMAP 406 extensions. To avoid conflict, the identifiers for these MUST be 407 a URI beginning with a domain owned by the vendor. Clients MUST 408 opt in to any specifications it wishes to use (see "Making an API 409 request"). 411 o *apiUrl*: "String" The URL to use for JMAP API requests. 413 o *downloadUrl*: "String" The URL endpoint to use when downloading 414 files (see the Download section of this spec), in [RFC6570] URI 415 Template (level 1) format. The URL MUST contain variables called 416 "blobId", MAY contain a variables called "accountId" and SHOULD 417 contain a variable called "name". 419 o *uploadUrl*: "String" The URL endpoint to use when uploading files 420 (see the Upload section of this spec), in [RFC6570] URI Template 421 (level 1) format. The URL MAY contain a variable called 422 "accountId". 424 o *eventSourceUrl*: "String" The URL to connect to for push events 425 (see the Push section of this spec). 427 To ensure future compatibility, other properties MAY be included on 428 the JMAP Session object. Clients MUST ignore any properties they are 429 not expecting. 431 2.1. Example 433 In the following example JMAP Session object, the user has access to 434 his own mail and contacts via JMAP, as well as read-only access to 435 shared mail from another user: 437 { 438 "username": "john@example.com", 439 "accounts": { 440 "13824": { 441 "name": "john@example.com", 442 "isReadOnly": false, 443 "hasDataFor": [ 444 "urn:ietf:params:jmap:mail", 445 "urn:ietf:params:jmap:contacts" 446 ] 447 }, 448 "97813": { 449 "name": "jane@example.com", 450 "isReadOnly": true, 451 "hasDataFor": [ "urn:ietf:params:jmap:mail" ] 452 } 453 }, 454 "primaryAccounts": { 455 "urn:ietf:params:jmap:mail": "13824", 456 "urn:ietf:params:jmap:contacts": "13824" 457 }, 458 "capabilities": { 459 "urn:ietf:params:jmap:core": { 460 "maxSizeUpload": 50000000, 461 "maxConcurrentUpload": 8, 462 "maxSizeRequest": 10000000, 463 "maxConcurrentRequest": 8, 464 "maxCallsInRequest": 32, 465 "maxObjectsInGet": 256, 466 "maxObjectsInSet": 128, 467 "collationAlgorithms": [ 468 "i;ascii-numeric", 469 "i;ascii-casemap", 470 "i;unicode-casemap" 471 ] 472 }, 473 ... 474 }, 475 "apiUrl": "https://jmap.example.com/api/", 476 "downloadUrl": "https://jmap.example.com/download/{accountId}/{blobId}/{name}", 477 "uploadUrl": "https://jmap.example.com/upload/{accountId}/", 478 "eventSourceUrl": "https://jmap.example.com/eventsource/" 479 } 480 2.2. Service Autodiscovery 482 There are two standardised autodiscovery methods in use for internet 483 protocols: 485 o *DNS SRV* ([RFC2782], [RFC6186] and [RFC6764]) 487 o *.well-known/servicename* ([RFC5785]) 489 A JMAP-supporting host for the domain "example.com" SHOULD publish a 490 SRV record "_jmap._tcp.example.com" which gives a _hostname_ and 491 _port_ (usually port "443"). The JMAP Session resource is then 492 "https://${hostname}[:${port}]/.well-known/jmap" (following any 493 redirects). 495 If the client has a username in the form of an email address, it MAY 496 use the domain portion of this to attempt autodiscovery of the JMAP 497 server. 499 3. Structured data exchange 501 The client may make an API request to the server to get or set 502 structured data. This request consists of an ordered series of 503 method calls. These are processed by the server, which then returns 504 an ordered series of responses. 506 3.1. Making an API request 508 To make an API request, the client makes an authenticated POST 509 request to the API resource, which is defined by the _apiUrl_ 510 property in the JMAP Session object. 512 The request MUST be of type "application/json" and consist of a 513 single JSON *Request* object. If successful, the response MUST also 514 be of type "application/json" and consist of a single *Response* 515 object. 517 3.2. The Request object 519 A *Request* object has the following properties: 521 o *using*: "String[]" The set of capabilities the client wishes to 522 use. The client MAY include capability identifiers even if the 523 method calls it makes do not utilise those capabilities. The 524 server advertises the set of specifications it supports in the 525 JMAP Session object, as keys on the _capabilities_ property. 527 o *methodCalls*: "Array[]" An array of method calls to process on 528 the server. The method calls MUST be processed sequentially, in 529 order. A *method call* is represented by an array containing 530 three elements: 532 1. A "String" *name* of the method to call. 534 2. An "Object" containing _named_ *arguments* for that method. 536 3. A *client id*: an arbitrary "String" to be echoed back with 537 the responses emitted by that method call (a method may return 538 1 or more responses, as it may make implicit calls to other 539 methods; all responses initiated by this method call get the 540 same client id in the response). 542 o *createdIds*: "String[String]" (optional) A map of (client- 543 specified) creation id to the id the server assigned when a record 544 was successfully created. As described later in this 545 specification, some records may have a property that contains the 546 id of another record. To allow more efficient network usage, you 547 can set this property to reference a record created earlier in the 548 same API request. Since the real id is unknown when the request 549 is created, the client can instead specify the creation id it 550 assigned, prefixed with a "#". As the server processes API 551 requests, any time it successfully creates a new record it adds to 552 this map the creation id, with the server-assigned real id as the 553 value. If it comes across a reference to a creation id in a 554 create/update, it looks it up in the map and replaces the 555 reference with the real id, if found. The client can pass an 556 initial value for this map as the _createdIds_ property of the 557 Request. This MAY be an empty object. If given in the request, 558 the response will also include a createdIds property, with any 559 additionally created ids added. This allows proxy servers to 560 easily split a JMAP request into multiple JMAP requests to send to 561 different servers. For example it could send the first two method 562 calls to server A, then the third to server B, before sending the 563 fourth to server A again. By passing the createdIds of the 564 previous response to the next request, it can ensure all of these 565 still resolve. 567 Future specifications MAY add further properties to the Request 568 object to extend the semantics. To ensure forwards compatibility, a 569 server MUST ignore any other properties it does not understand on the 570 JMAP request object. 572 3.2.1. Example request 574 { 575 "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail" ], 576 "methodCalls": [ 577 ["method1", {"arg1": "arg1data", "arg2": "arg2data"}, "c1"], 578 ["method2", {"arg1": "arg1data"}, "c2"], 579 ["method3", {}, "c3"] 580 ] 581 } 583 3.3. Vendor-specific extensions 585 Individual services will have custom features they wish to expose 586 over JMAP. This may take the form of extra data types and/or methods 587 not in the spec, or extra arguments to JMAP methods, or extra 588 properties on existing data types (which may also appear in arguments 589 to methods that take property names). 591 The server can advertise custom extensions it supports by including 592 the identifiers in the capabilities object. Identifiers for vendor 593 extensions MUST be a URL belonging to a domain owned by the vendor, 594 to avoid conflict. The URL SHOULD resolve to documentation for the 595 changes the extension makes. 597 To ensure compatibility with clients that don't know about a specific 598 custom extension, and for compatibility with future versions of JMAP, 599 to use an extension the client MUST opt in by passing the appropriate 600 capability identifier in the _using_ array of the Request object. 601 The server MUST only follow the specifications that are opted-into 602 and behave as though it does not implement anything else when 603 processing a request. 605 3.4. The Response object 607 A *Response* object has the following properties: 609 o *methodResponses*: "Array[]" An array of responses, in the same 610 format as the _methodCalls_ on the request object. The output of 611 the methods MUST be added to the _methodResponses_ array in the 612 same order as the methods are processed. 614 o *createdIds*: "String[String]" (optional; only returned if given 615 in request) A map of (client-specified) creation id to the id the 616 server assigned when a record was successfully created. This 617 includes all values passed in the request, as well as any 618 additional ones added for newly created records. 620 Unless otherwise specified, if the method call completed successfully 621 its response name is the same as the method name in the request. 623 3.4.1. Example response: 625 { 626 "methodResponses": [ 627 ["method1", {"arg1": 3, "arg2": "foo"}, "c1"], 628 ["method2", {"isBlah": true}, "c2"], 629 ["anotherResponseFromMethod2", { 630 "data": 10, 631 "yetmoredata": "Hello" 632 }, "c2"], 633 ["error", {"type":"unknownMethod"}, "c3"] 634 ] 635 } 637 3.5. Omitting arguments 639 An argument to a method may be specified to have a default value. If 640 omitted by the client, the server MUST treat the method call the same 641 as if the default value had been specified. Similarly, the server 642 MAY omit any argument in a response which has the default value. 644 Unless otherwise specified in a method description, "null" is the 645 default value for any argument in a request or response where this is 646 allowed by the type signature. Other arguments may only be omitted 647 if an explicit default value is defined in the method description. 649 3.6. Errors 651 3.6.1. Error responses 653 When an HTTP error response is returned to the client, the server 654 SHOULD return a JSON "problem details" object in the response body, 655 as per [RFC7807]. Every JSON "problem details" object MUST include a 656 "type" member with a URI either one of the following values, or a 657 value defined in a future RFC, or a value beginning with a domain 658 owned by the vendor. 660 o "urn:ietf:params:jmap:error:unknowncapability" The client included 661 a capability in the "using" property of the request that the 662 server does not support. 664 o "urn:ietf:params:jmap:error:notjson" The content type of the 665 request was not "application/json" or the request did not parse as 666 I-JSON. 668 o "urn:ietf:params:jmap:error:notrequest" The request parsed as JSON 669 but did not match the structure of the Request object. 671 3.6.2. Method-level errors 673 If a method encounters an error, the appropriate "error" response 674 MUST be inserted at the current point in the _methodResponses_ array 675 and, unless otherwise specified, further processing MUST NOT happen 676 within that method call. 678 Any further method calls in the request MUST then be processed as 679 normal. Errors at the method level MUST NOT generate an HTTP-level 680 error. 682 An "error" response looks like this: 684 ["error", { 685 "type": "unknownMethod" 686 }, "client-id"] 688 The response name is "error", and it MUST have a type property. 689 Other properties may be present with further information; these are 690 detailed in the error type descriptions where appropriate. 692 With the exception of "serverPartialFail", the externally-visible 693 state of the server MUST NOT have changed if an error is returned at 694 the method level. 696 The following error types are defined which may be returned for any 697 method call where appropriate: 699 "serverUnavailable": Some internal server resource was temporarily 700 unavailable. Attempting the same operation later (perhaps after a 701 backoff with a random factor) may succeed. 703 "serverFail": An unexpected or unknown error occurred during the 704 processing of the call. A _description_ property should provide more 705 details about the error. The method call made no changes to the 706 server's state. Attempting the same operation again is expected to 707 fail again. Contacting the service administrator is likely necessary 708 to resolve this problem if it is persistent. 710 "serverPartialFail": Some, but not all expected changes described by 711 the method occurred. The client MUST re-synchronise impacted data to 712 determine server state. Use of this error is strongly discouraged. 714 "unknownMethod": The server does not recognise this method name. 716 "invalidArguments": One of the arguments is of the wrong type or 717 otherwise invalid, or a required argument is missing. A 718 "description" property MAY be present to help debug with an 719 explanation of what the problem was. This is a non-localised string, 720 and is not intended to be shown directly to end users. 722 "forbidden": The method and arguments are valid, but executing the 723 method would violate an ACL or other permissions policy. 725 "accountNotFound": An _accountId_ was included with the method call 726 that does not correspond to a valid account, or _accountId_ was null 727 but there is no primary account for the capability that defines the 728 data type. 730 "accountNotSupportedByMethod": An _accountId_ given corresponds to a 731 valid account, but the account does not support this data type. 733 "accountReadOnly": This method call would modify state in an account 734 that has "isReadOnly == true". 736 Further possible errors for a particular method are specified in the 737 method descriptions. 739 Further general errors MAY be defined in future RFCs. Should a 740 client receive an error type it does not understand, it MUST treat it 741 the same as the "serverFail" type. 743 3.7. References to previous method results 745 To allow clients to make more efficient use of the network and avoid 746 round trips, an argument to one method can be taken from the result 747 of a previous method call. 749 To do this, the client prefixes the argument name with "#". The 750 value is a _ResultReference_ object as described below. When 751 processing a method call, the server MUST first check the arguments 752 object for any names beginning with "#". If found, the back 753 reference should be resolved and the value used as the "real" 754 argument. The method is then processed as normal. If any back 755 reference fails to resolve, the whole method MUST be rejected with a 756 "resultReference" error. If an argument object contains the same 757 argument name in normal and referenced form (e.g. "foo" and "#foo"), 758 the method MUST return an "invalidArguments" error. 760 A *ResultReference* object has the following properties: 762 o *resultOf*: "String" The client id of the method call to get the 763 result from (the string given as the third item in the array for a 764 method call). 766 o *name*: "String" The expected name of the response. 768 o *path*: "String" A pointer into the arguments. This is an 769 [RFC6901] JSON Pointer, except it also allows the use of "*" to 770 map through an array (see description below). 772 To resolve: 774 1. Find the first response with a client id identical to the 775 _resultOf_ property of the _ResultReference_ in the 776 _methodResponses_ array from previously processed method calls in 777 the same request. If none, evaluation fails. 779 2. If the response name is not identical to the _name_ property of 780 the _ResultReference_, evaluation fails. 782 3. Apply the _path_ to the arguments object of the response (the 783 second item in the response array) following the [RFC6901] JSON 784 Pointer algorithm, except with the following addition in 785 Section 4 (Evaluation): 787 If the currently referenced value is a JSON array, the reference 788 token may be exactly the single character "*", making the new 789 referenced value the result of applying the rest of the JSON pointer 790 tokens to every item in the array and returning the results in the 791 same order in a new array. If the result of applying the rest of the 792 pointer tokens to a value was itself an array, its items should be 793 included individually in the output rather than including the array 794 itself (i.e. the result is flattened from an array of arrays to a 795 single array). 797 As a simple example, suppose we have the following API request 798 _methodCalls_: 800 [[ "Foo/changes", { 801 "sinceState": "abcdef" 802 }, "t0" ], 803 [ "Foo/get", { 804 "#ids": { 805 "resultOf": "t0", 806 "name": "Foo/changes", 807 "path": "/created" 808 } 809 }, "t1" ]] 811 After executing the first method call the _methodResponses_ array is: 813 [[ "Foo/changes", { 814 "accountId": "1", 815 "oldState": "abcdef", 816 "newState": "123456", 817 "hasMoreChanges": false, 818 "created": [ "f1", "f4" ], 819 "updated": [], 820 "destroyed": [] 821 }, "t0" ]] 823 So to execute the Foo/get call, we look through the arguments and 824 find there is one with a "#" prefix. To resolve this, we apply the 825 algorithm above: 827 1. Find the first response with client id "t0". The Foo/changes 828 response fulfils this criterion. 830 2. Check the response name is the same as in the result reference. 831 It is, so this is fine. 833 3. Apply the _path_ as a JSON pointer to the arguments object. This 834 simply selects the "created" property, so the result of 835 evaluating is: "[ "f1", "f4" ]" 837 The JMAP server now continues to process the Foo/get call as though 838 the arguments were: 840 { 841 "ids": [ "f1", "f4" ] 842 } 844 Now a more complicated example using the JMAP Mail data model: fetch 845 the "from"/"date"/"subject" for every email in the first 10 threads 846 in the Inbox (sorted newest first): 848 [[ "Email/query", { 849 "filter": { "inMailbox": "id_of_inbox" }, 850 "sort": [{ "property": "receivedAt", "isAscending": false }], 851 "collapseThreads": true, 852 "position": 0, 853 "limit": 10 854 }, "t0" ], 855 [ "Email/get", { 856 "#ids": { 857 "resultOf": "t0", 858 "name": "Email/query", 859 "path": "/ids" 860 }, 861 "properties": [ "threadId" ] 862 }, "t1" ], 863 [ "Thread/get", { 864 "#ids": { 865 "resultOf": "t1", 866 "name": "Email/get", 867 "path": "/list/*/threadId" 868 } 869 }, "t2" ], 870 [ "Email/get", { 871 "#ids": { 872 "resultOf": "t2", 873 "name": "Thread/get", 874 "path": "/list/*/emailIds" 875 }, 876 "properties": [ "from", "receivedAt", "subject" ] 877 }, "t3" ]] 879 After executing the first 3 method calls the _methodResponses_ array 880 might be: 882 [[ "Email/query", { 883 "accountId": "1", 884 "filter": { "inMailbox": "id_of_inbox" }, 885 "sort": [{ "property": "receivedAt", "isAscending": false }], 886 "collapseThreads": true, 887 "queryState": "abcdefg", 888 "canCalculateChanges": true, 889 "position": 0, 890 "total": 101, 891 "ids": [ "msg1023", "msg223", "msg110", "msg93", "msg91", "msg38", "msg36", "msg33", "msg11", "msg1" ] 892 }, "t0" ], 893 [ "Email/get", { 894 "accountId": "1", 895 "state": "123456", 896 "list": [{ 897 "id": "msg1023", 898 "threadId": "trd194", 899 }, { 900 "id": "msg223", 901 "threadId": "trd114" 902 }, 903 ... 904 ], 905 "notFound": [] 906 }, "t1" ], 907 [ "Thread/get", { 908 "accountId": "1", 909 "state": "123456", 910 "list": [{ 911 "id: "trd194", 912 "emailIds": [ "msg1020", "msg1021", "msg1023" ] 913 }, { 914 "id: "trd114", 915 "emailIds": [ "msg201", "msg223" ] 916 }, 917 ... 918 ], 919 "notFound": [] 920 }, "t2" ]] 922 So to execute the final Email/get call, we look through the arguments 923 and find there is one with a "#" prefix. To resolve this, we apply 924 the algorithm: 926 1. Find the first response with client id "t2". The "Thread/get" 927 response fulfils this criterion. 929 2. "Thread/get" is the name specified in the result reference, so 930 this is fine. 932 3. Apply the _path_ as a JSON pointer to the arguments object. 933 Token-by-token: a) "list": get the array of thread objects b) 934 "*": for each of the items in the array: 936 i) `emailIds`: get the array of email ids 937 ii) Concatenate these into a single array of all the ids in the result. 939 The JMAP server now continues to process the Email/get call as though 940 the arguments were: 942 { 943 "ids": [ "msg1020", "msg1021", "msg1023", "msg201", "msg223", ... ], 944 "properties": [ "from", "receivedAt", "subject" ] 945 } 947 3.8. Security 949 As always, the server must be strict about data received from the 950 client. Arguments need to be checked for validity; a malicious user 951 could attempt to find an exploit through the API. In case of invalid 952 arguments (unknown/insufficient/wrong type for data etc.) the method 953 MUST return an "invalidArguments" error and terminate. 955 3.9. Concurrency 957 Method calls within a single request MUST be executed in order. 958 However, method calls from different concurrent API requests may be 959 interleaved. This means that the data on the server may change 960 between two method calls within a single API request. 962 4. Standard methods and naming convention 964 JMAP provides a uniform interface for creating, retrieving, updating 965 and deleting objects of a particular type. For a "Foo" data type, 966 records of that type would be fetched via a Foo/get call and modified 967 via a Foo/set call. Delta updates may be fetched via a Foo/changes 968 call. These methods all follow a standard format as described below. 970 4.1. /get 972 Objects of type *Foo* are fetched via a call to _Foo/get_. 974 It takes the following arguments: 976 o *accountId*: "String|null" The id of the Account to use. If 977 "null", the primary account for the capability that defines the 978 data type is used. 980 o *ids*: "String[]|null" The ids of the Foo objects to return. If 981 "null" then *all* records of the data type are returned, if this 982 is supported for that data type. 984 o *properties*: "String[]|null" If supplied, only the properties 985 listed in the array are returned for each Foo object. If "null", 986 all properties of the object are returned. The id of the object 987 is *always* returned, even if not explicitly requested. If an 988 invalid property is requested, the call MUST be rejected with an 989 "invalidArguments" error. 991 The response has the following arguments: 993 o *accountId*: "String" The id of the account used for the call. 995 o *state*: "String" A string representing the state on the server 996 for *all* the data of this type in the account (not just the 997 objects returned in this call). If the data changes, this string 998 MUST change. If the Foo data is unchanged, servers SHOULD return 999 the same state string on subsequent requests for this data type. 1000 When a client receives a response with a different state string to 1001 a previous call, it MUST either throw away all currently cached 1002 objects for the type, or call _Foo/changes_ to get the exact 1003 changes. 1005 o *list*: "Foo[]" An array of the Foo objects requested. This is 1006 the *empty array* if no objects were found, or if the _ids_ 1007 argument passed in was also the empty array. The results MAY be 1008 in a different order to the _ids_ in the request arguments. If an 1009 identical id is included more than once in the request, the server 1010 MUST only include it once in either the _list_ or _notFound_ 1011 argument of the response. 1013 o *notFound*: "String[]" This array contains the ids passed to the 1014 method for records that do not exist. The array is empty if all 1015 requested ids were found, or if the _ids_ argument passed in was 1016 either "null" or the empty array. 1018 The following additional error may be returned instead of the _Foo/ 1019 get_ response: 1021 "requestTooLarge": The number of _ids_ requested by the client 1022 exceeds the maximum number the server is willing to process in a 1023 single method call. 1025 4.2. /changes 1027 When the state of the set of Foo records changes on the server 1028 (whether due to creation, updates or deletion), the _state_ property 1029 of the _Foo/get_ response will change. The _Foo/changes_ method 1030 allows a client to efficiently update the state of its Foo cache to 1031 match the new state on the server. It takes the following arguments: 1033 o *accountId*: "String|null" The id of the Account to use. If 1034 "null", the primary account for the capability that defines the 1035 data type is used. 1037 o *sinceState*: "String" The current state of the client. This is 1038 the string that was returned as the _state_ argument in the _Foo/ 1039 get_ response. The server will return the changes that have 1040 occurred since this state. 1042 o *maxChanges*: "Number|null" The maximum number of ids to return in 1043 the response. The server MAY choose to return fewer than this 1044 value, but MUST NOT return more. If not given by the client, the 1045 server may choose how many to return. If supplied by the client, 1046 the value MUST be a positive integer greater than 0. If a value 1047 outside of this range is given, the server MUST reject the call 1048 with an "invalidArguments" error. 1050 The response has the following arguments: 1052 o *accountId*: "String" The id of the account used for the call. 1054 o *oldState*: "String" This is the _sinceState_ argument echoed 1055 back; the state from which the server is returning changes. 1057 o *newState*: "String" This is the state the client will be in after 1058 applying the set of changes to the old state. 1060 o *hasMoreChanges*: "Boolean" If "true", the client may call _Foo/ 1061 changes_ again with the _newState_ returned to get further 1062 updates. If "false", _newState_ is the current server state. 1064 o *created*: "String[]" An array of ids for records which have been 1065 created since the old state. 1067 o *updated*: "String[]" An array of ids for records which have been 1068 updated since the old state. 1070 o *destroyed*: "String[]" An array of ids for records which have 1071 been destroyed since the old state. 1073 If a _maxChanges_ is supplied, or set automatically by the server, 1074 the server MUST ensure the number of ids returned across _created_, 1075 _updated_ and _destroyed_ does not exceed this limit. If there are 1076 more changes than this between the client's state and the current 1077 server state, the update returned SHOULD generate an update to take 1078 the client to an intermediate state, from which the client can 1079 continue to call _Foo/changes_ until it is fully up to date. If it 1080 is unable to calculate an intermediate state, it MUST return a 1081 "cannotCalculateChanges" error response instead. 1083 If a Foo record has been created AND destroyed since the old state, 1084 the server SHOULD remove the id from the response entirely, but MAY 1085 include it in the _destroyed_ list, and if so MAY also include it in 1086 the _created_ list. 1088 If a Foo record has been updated AND destroyed since the old state, 1089 the server SHOULD just return the id in the _destroyed_ list, but MAY 1090 return it in the _updated_ list as well. 1092 The following additional errors may be returned instead of the _Foo/ 1093 changes_ response: 1095 "cannotCalculateChanges": The server cannot calculate the changes 1096 from the state string given by the client. Usually due to the 1097 client's state being too old, or the server being unable to produce 1098 an update to an intermediate state when there are too many updates. 1099 The client MUST invalidate its Foo cache. 1101 Maintaining state to allow calculation of _Foo/changes_ can be 1102 expensive for the server, but always returning 1103 _cannotCalculateChanges_ severely increases network traffic and 1104 resource usage for the client. To allow efficient sync, servers 1105 SHOULD be able to calculate changes from any state string that was 1106 given to a client within the last 30 days (but of course may support 1107 calculating updates from states older than this). 1109 4.3. /set 1111 Modifying the state of Foo objects on the server is done via the 1112 _Foo/set_ method. This encompasses creating, updating and destroying 1113 Foo records. This allows the server to sort out ordering and 1114 dependencies that may exist if doing multiple operations at once (for 1115 example to ensure there is always a minimum number of a certain 1116 record type). 1118 The _Foo/set_ method takes the following arguments: 1120 o *accountId*: "String|null" The id of the Account to use. If 1121 "null", the primary account for the capability that defines the 1122 data type is used. 1124 o *ifInState*: "String|null" This is a state string as returned by 1125 the _Foo/get_ method. If supplied, the string must match the 1126 current state, otherwise the method will be aborted and a 1127 "stateMismatch" error returned. If "null", any changes will be 1128 applied to the current state. 1130 o *create*: "String[Foo]|null" A map of _creation id_ (an arbitrary 1131 string set by the client) to Foo objects, or "null" if no objects 1132 are to be created. The Foo object type definition MAY define 1133 default values for properties. Any such property MAY be omitted 1134 by the client. The client MUST omit any properties that may only 1135 be set by the server (for example, the _id_ property on most 1136 object types). 1138 o *update*: "String[PatchObject]|null" A map of id to a Patch object 1139 to apply to the current Foo object with that id, or "null" if no 1140 objects are to be updated. A _PatchObject_ is of type 1141 "String[*]", and represents an unordered set of patches. The keys 1142 are a path in [RFC6901] JSON pointer format, with an implicit 1143 leading "/" (i.e. prefix each key with "/" before applying the 1144 JSON pointer evaluation algorithm). All paths MUST also conform 1145 to the following restrictions; if there is any violation, the 1146 update MUST be rejected with an "invalidPatch" error: 1148 * The pointer MUST NOT reference inside an array (i.e. you MUST 1149 NOT insert/delete from an array; the array MUST be replaced in 1150 its entirety instead). 1152 * All parts prior to the last (i.e. the value after the final 1153 slash) MUST already exist on the object being patched. 1155 * There MUST NOT be two patches in the PatchObject where the 1156 pointer of one is the prefix of the pointer of the other, e.g. 1157 "alerts/1/offset" and "alerts". 1159 The value associated with each pointer determines how to apply 1160 that patch: 1162 * If "null", set to the default value if specified for this 1163 property, otherwise remove the property from the patched 1164 object. If the key is not present in the parent, this a no-op. 1166 * Anything else: The value to set for this property (this may be 1167 a replacement or addition to the object being patched). 1169 Any server-set properties MAY be included in the patch if their 1170 value is identical to the current server value (before applying 1171 the patches to the object). Otherwise, the update MUST be 1172 rejected with an _invalidProperties_ SetError. This patch 1173 definition is designed such that an entire Foo object is also a 1174 valid PatchObject. The client MAY choose to optimise network 1175 usage by just sending the diff, or MAY just send the whole object; 1176 the server processes it the same either way. 1178 o *destroy*: "String[]|null" A list of ids for Foo objects to 1179 permanently delete, or "null" if no objects are to be destroyed. 1181 Each creation, modification or destruction of an object is considered 1182 an atomic unit. It is permissible for the server to commit changes 1183 to some objects but not others, however it is not permissible to only 1184 commit part of an update to a single record (e.g. update a _name_ 1185 property but not a _count_ property, if both are supplied in the 1186 update object). 1188 The final state MUST be valid after the Foo/set is finished, however 1189 the server may have to transition through invalid intermediate states 1190 (not exposed to the client) while processing the individual 1191 create/update/destroy requests. For example, suppose there is a 1192 "name" property that must be unique. A single method call could 1193 rename an object A => B, and simultaneously rename another object B 1194 => A. If the final state is valid, this is allowed. Otherwise, each 1195 creation, modification or destruction of an object should be 1196 processed sequentially and accepted/rejected based on the current 1197 server state. 1199 If a create, update or destroy is rejected, the appropriate error 1200 MUST be added to the notCreated/notUpdated/notDestroyed property of 1201 the response and the server MUST continue to the next create/update/ 1202 destroy. It does not terminate the method. 1204 If an id given cannot be found, the update or destroy MUST be 1205 rejected with a "notFound" set error. 1207 The server MAY skip an update (rejecting it with a "willDestroy" 1208 SetError) if that object is destroyed in the same /set request. 1210 Some record objects may hold references to others (foreign keys). 1211 When records are created or modified, they may reference other 1212 records being created _in the same API request_ by using the creation 1213 id prefixed with a "#". The order of the method calls in the request 1214 by the client MUST be such that the record being referenced is 1215 created in the same or an earlier call. The server thus never has to 1216 look ahead. Instead, while processing a request (a series of method 1217 calls), the server MUST keep a simple map for the duration of the 1218 request of creation id to record id for each newly created record, so 1219 it can substitute in the correct value if necessary in later method 1220 calls. 1222 Creation ids are not scoped by type but are a single map for all 1223 types. A client SHOULD NOT reuse a creation id anywhere in the same 1224 API request. If a creation id is reused, the server MUST map the 1225 creation id to the most recently created item with that id. To allow 1226 easy proxying of API requests, an initial set of creation id to real 1227 id values may be passed with a request (see The Request object 1228 specification above). 1230 The response has the following arguments: 1232 o *accountId*: "String" The id of the account used for the call. 1234 o *oldState*: "String|null" The state string that would have been 1235 returned by _Foo/get_ before making the requested changes, or 1236 "null" if the server doesn't know what the previous state string 1237 was. 1239 o *newState*: "String" The state string that will now be returned by 1240 _Foo/get_. 1242 o *created*: "String[Foo]|null" A map of the creation id to an 1243 object containing any properties of the created Foo object that 1244 were not sent by the client. This includes all server-set 1245 properties (such as the _id_ in most object types) and any 1246 properties that were omitted by the client and so set to a default 1247 by the server. This argument is "null" if no Foo objects were 1248 successfully created. 1250 o *updated*: "String[Foo|null]|null" The _keys_ in this map are the 1251 ids of all Foos that were successfully updated, or "null" if none 1252 successful. The _value_ for each id is a Foo object containing 1253 any property that changed in a way _not_ explicitly requested by 1254 the _PatchObject_ sent to the server, or "null" if none. This 1255 lets the client know of any changes to server-set or computed 1256 properties. 1258 o *destroyed*: "String[]|null" A list of Foo ids for records that 1259 were successfully destroyed, or "null" if none successful. 1261 o *notCreated*: "String[SetError]|null" A map of creation id to a 1262 SetError object for each record that failed to be created, or 1263 "null" if all successful. 1265 o *notUpdated*: "String[SetError]|null" A map of Foo id to a 1266 SetError object for each record that failed to be updated, or 1267 "null" if all successful. 1269 o *notDestroyed*: "String[SetError]|null" A map of Foo id to a 1270 SetError object for each record that failed to be destroyed, or 1271 "null" if all successful. 1273 A *SetError* object has the following properties: 1275 o *type*: "String" The type of error. 1277 o *description*: "String|null" A description of the error to help 1278 debug with an explanation of what the problem was. This is a non- 1279 localised string, and is not intended to be shown directly to end 1280 users. 1282 The following SetError types are defined and may be returned for set 1283 operations on any record type where appropriate: 1285 o "forbidden": (create; update; destroy) The create/update/destroy 1286 would violate an ACL or other permissions policy. 1288 o "overQuota": (create) The create would exceed a server-defined 1289 limit on the number or total size of objects of this type. 1291 o "rateLimit": (create) Too many objects of this type have been 1292 created recently, and a server-defined rate limit has been 1293 reached. It may work if tried again later. 1295 o "notFound": (update; destroy) The id given cannot be found. 1297 o "invalidPatch": (update) The PatchObject given to update the 1298 record was not a valid patch (see the patch description). 1300 o "willDestroy" (update) The client requested an object be both 1301 updated and destroyed in the same /set request, and the server has 1302 decided to therefore ignore the update. 1304 o "invalidProperties": (create; update) The record given is invalid 1305 in some way. For example: 1307 * It contains properties which are invalid according to the type 1308 specification of this record type. 1310 * It contains a property that may only be set by the server (e.g. 1311 "id") and are different to the current value. Note, to allow 1312 clients to pass whole objects back, it is not an error to 1313 include a server-set property so long as the value is identical 1314 to the current value on the server (or the value that will be 1315 set by the server if a create). 1317 * There is a reference to another record (foreign key) and the 1318 given id does not correspond to a valid record. 1320 The SetError object SHOULD also have a property called 1321 _properties_ of type "String[]" that lists *all* the properties 1322 that were invalid. Individual methods MAY specify more specific 1323 errors for certain conditions that would otherwise result in an 1324 invalidProperties error. If the condition of one of these is met, 1325 it MUST be returned instead of the invalidProperties error. 1327 o "singleton": (create; destroy) This is a singleton type, so you 1328 cannot create another one or destroy the existing one. 1330 Other possible SetError types MAY be given in specific method 1331 descriptions. Other properties MAY also be present on the _SetError_ 1332 object, as described in the relevant methods. 1334 The following additional errors may be returned instead of the _Foo/ 1335 set_ response: 1337 "requestTooLarge": The total number of objects to create, update or 1338 destroy exceeds the maximum number the server is willing to process 1339 in a single method call. 1341 "stateMismatch": An "ifInState" argument was supplied and it does not 1342 match the current state. 1344 4.4. /query 1346 For data sets where the total amount of data is expected to be very 1347 small, clients can just fetch the complete set of data and then do 1348 any sorting/filtering locally. However, for large data sets (e.g. 1349 multi-gigabyte mailboxes), the client needs to be able to 1350 search/sort/window the data type on the server. 1352 A query on the set of Foos in an account is made by calling _Foo/ 1353 query_. This takes a number of arguments to determine which records 1354 to include, how they should be sorted, and which part of the result 1355 should be returned (the full list may be _very_ long). The result is 1356 returned as a list of Foo ids. 1358 A call to _Foo/query_ takes the following arguments: 1360 o *accountId*: "String|null" The id of the Account to use. If 1361 "null", the primary account for the capability that defines the 1362 data type is used. 1364 o *filter*: "FilterOperator|FilterCondition|null" Determines the set 1365 of Foos returned in the results. If "null", all objects in the 1366 account of this type are included in the results. A 1367 *FilterOperator* object has the following properties: 1369 * *operator*: "String" This MUST be one of the following strings: 1370 "AND"/"OR"/"NOT": 1372 + *AND*: all of the conditions must match for the filter to 1373 match. 1375 + *OR*: at least one of the conditions must match for the 1376 filter to match. 1378 + *NOT*: none of the conditions must match for the filter to 1379 match. 1381 * *conditions*: "(FilterOperator|FilterCondition)[]" The 1382 conditions to evaluate against each email. 1384 A *FilterCondition* is an "object", whose allowed properties and 1385 semantics depend on the data type and is defined in the _/query_ 1386 method specification for that type. 1388 o *sort*: "Comparator[]|null" Lists the names of properties to 1389 compare between two Foo records, and how to compare them, to 1390 determine which comes first in the sort. If two Foo records have 1391 an identical value for the first comparator, the next comparator 1392 will be considered and so on. If all comparators are the same 1393 (this includes the case where an empty array or "null" is given as 1394 the _sort_ argument), the sort order is server-dependent, but MUST 1395 be stable between calls to Foo/query. A *Comparator* has the 1396 following properties: 1398 * *property*: "String" The name of the property on the Foo 1399 objects to compare. 1401 * *isAscending*: "Boolean" (optional; default: "true") If true, 1402 sort in ascending order. If false, reverse the comparator's 1403 results to sort in descending order. 1405 * *collation*: "String" (optional; default is server-dependent) 1406 The identifier, as registered in the collation registry defined 1407 in [RFC4790], for the algorithm to use when comparing the order 1408 of strings. The algorithms the server supports are advertised 1409 in the capabilities object returned with the JMAP Session 1410 object. If omitted, the default algorithm is server-dependent, 1411 but: 1413 1. It MUST be unicode-aware. 1415 2. It SHOULD have reasonable default behavior for many 1416 languages when the user's language is unknown. 1418 3. It MAY be selected based on out-of-band information about 1419 the user's language/locale. 1421 4. It SHOULD be case-insensitive where such a concept makes 1422 sense for a language/locale. 1424 The "i;unicode-casemap" collation ([RFC5051]) and the Unicode 1425 Collation Algorithm () 1426 are two examples that fulfil these criterion. When the 1427 property being compared is not a string, the _collation_ 1428 property is ignored and the following comparison rules apply 1429 based on the type. In ascending order: 1431 + "Boolean": "false" comes before "true". 1433 + "Number": A lower number comes before a higher number. 1435 + "Date"/"UTCDate": The earlier date comes first. 1437 o *position*: "Number" (default: "0") The 0-based index of the first 1438 id in the full list of results to return. If a negative value is 1439 given, it is an offset from the end of the list. Specifically, 1440 the negative value MUST be added to the total number of results 1441 given the filter, and if still negative clamped to "0". This is 1442 now the 0-based index of the first id to return. If the index is 1443 greater than or equal to the total number of objects in the 1444 results list then the _ids_ array in the response will be empty, 1445 but this is not an error. 1447 o *anchor*: "String|null" A Foo id. If supplied the _position_ 1448 argument is ignored. The index of this id in the results will be 1449 used in combination with the "anchorOffset" argument to determine 1450 the index of the first result to return (see below for more 1451 details). 1453 o *anchorOffset*: "Number|null" The index of the first result to 1454 return relative to the index of the anchor. This MAY be negative. 1455 For example, "-1" means the first Foo before the anchor Foo should 1456 be the first result in the results returned (see below for more 1457 details). 1459 o *limit*: "Number|null" The maximum number of results to return. 1460 If "null", no limit presumed. The server MAY choose to enforce a 1461 maximum "limit" argument. In this case, if a greater value is 1462 given (or if it is "null"), the limit should be clamped to the 1463 maximum; since the total number of results in the query is 1464 returned, the client can determine if it has received all the 1465 results. If a negative value is given, the call MUST be rejected 1466 with an "invalidArguments" error. 1468 If an *anchor* argument is given, then after filtering and sorting 1469 the anchor is looked for in the results. If found, the *anchor 1470 offset* is then added to its index. If the resulting index is now 1471 negative, it is clamped to 0. This index is now used exactly as 1472 though it were supplied as the "position" argument. If the anchor is 1473 not found, the call is rejected with an "anchorNotFound" error. 1475 If an _anchor_ is specified, any position argument supplied by the 1476 client MUST be ignored. If _anchorOffset_ is "null", it defaults to 1477 "0". If no _anchor_ is supplied, any anchor offset argument MUST be 1478 ignored. 1480 A client can use _anchor_ instead of _position_ to find the index of 1481 an id within a large set of results. 1483 The response has the following arguments: 1485 o *accountId*: "String" The id of the account used for the call. 1487 o *filter*: "FilterOperator|FilterCondition|null" The filter used. 1488 Echoed back from the call. 1490 o *sort*: "Comparator[]|null" The sort options used. Echoed back 1491 from the call. 1493 o *queryState*: "String" A string encoding the current state of the 1494 query on the server. This string MUST change if the results of 1495 the query (i.e. the matching ids and their sort order) have 1496 changed. The queryState string MAY change if something has 1497 changed on the server which means the results may have changed but 1498 the server doesn't know for sure. The queryState string only 1499 represents the ordered list of ids that match the particular query 1500 (including its sort/filter). There is no requirement for it to 1501 change if a property on an object matching the query changes but 1502 the query results are unaffected (indeed, it is more efficient if 1503 the queryState string does not change in this case). The 1504 queryState string only has meaning when compared to future 1505 responses to a query with the same type/sort/filter, or when used 1506 with /queryChanges to fetch changes. Should a client receive back 1507 a response with a different queryState string to a previous call, 1508 it MUST either throw away the currently cached query and fetch it 1509 again (note, this does not require fetching the records again, 1510 just the list of ids) or, call _Foo/queryChanges_ to get the 1511 difference. 1513 o *canCalculateChanges*: "Boolean" This is "true" if the server 1514 supports calling _Foo/queryChanges_ with these "filter"/"sort" 1515 parameters. Note, this does not guarantee that the _Foo/ 1516 queryChanges_ call will succeed, as it may only be possible for a 1517 limited time afterwards due to server internal implementation 1518 details. 1520 o *position*: "Number" The 0-based index of the first result in the 1521 "ids" array within the complete list of query results. 1523 o *total*: "Number" The total number of foos in the results (given 1524 the _filter_). 1526 o *ids*: "String[]" The list of ids for each foo in the query 1527 results, starting at the index given by the _position_ argument of 1528 this response, and continuing until it hits the end of the results 1529 or reaches the "limit" number of ids. If _position_ is >= 1530 _total_, this MUST be the empty list. 1532 The following additional errors may be returned instead of the _Foo/ 1533 query_ response: 1535 "anchorNotFound": An anchor argument was supplied, but it cannot be 1536 found in the results of the query. 1538 "unsupportedSort": The _sort_ is syntactically valid, but includes a 1539 property the server does not support sorting on, or a collation 1540 method it does not recognise. 1542 "unsupportedFilter": The _filter_ is syntactically valid, but the 1543 server cannot process it. 1545 4.5. /queryChanges 1547 The "Foo/queryChanges" call allows a client to efficiently update the 1548 state of any cached foo query to match the new state on the server. 1549 It takes the following arguments: 1551 o *accountId*: "String|null" The id of the account to use. If 1552 "null", the primary account for the capability that defines the 1553 data type will be used. 1555 o *filter*: "FilterOperator|FilterCondition|null" The filter 1556 argument that was used with _Foo/query_. 1558 o *sort*: "Comparator[]|null" The sort argument that was used with 1559 _Foo/query_. 1561 o *sinceQueryState*: "String" The current state of the query in the 1562 client. This is the string that was returned as the _queryState_ 1563 argument in the _Foo/query_ response with the same sort/filter. 1564 The server will return the changes made to the query since this 1565 state. 1567 o *maxChanges*: "Number|null" The maximum number of changes to 1568 return in the response. See error descriptions below for more 1569 details. 1571 o *upToId*: "String|null" The last (highest-index) id the client 1572 currently has cached from the query results. When there are a 1573 large number of results, in a common case the client may have only 1574 downloaded and cached a small subset from the beginning of the 1575 results. If the sort and filter are both only on immutable 1576 properties, this allows the server to omit changes after this 1577 point in the results, which can significantly increase efficiency. 1578 If they are not immutable, this argument is ignored. 1580 The response has the following arguments: 1582 o *accountId*: "String" The id of the account used for the call. 1584 o *filter*: "FilterOperator|FilterCondition|null" The filter used. 1585 Echoed back from the call. 1587 o *sort*: "Comparator[]|null" The sort options used. Echoed back 1588 from the call. 1590 o *oldQueryState*: "String" This is the "sinceQueryState" argument 1591 echoed back; the state from which the server is returning changes. 1593 o *newQueryState*: "String" This is the state the query will be in 1594 after applying the set of changes to the old state. 1596 o *upToId*: "String|null" Echoed back from the call. 1598 o *total*: "Number" The total number of foos in the results (given 1599 the _filter_). 1601 o *removed*: "String[]" The _id_ for every foo that was in the query 1602 results in the old state and is not in the results in the new 1603 state. If the sort and filter are both only on immutable 1604 properties and an _upToId_ is supplied and exists in the results, 1605 any ids that were removed but have a higher index than _upToId_ 1606 SHOULD be omitted. If the server cannot calculate this exactly, 1607 the server MAY return extra foos in addition that may have been in 1608 the old results but are not in the new results. If the _filter_ 1609 or _sort_ includes a mutable property, the server MUST include all 1610 foos in the current results for which this property MAY have 1611 changed. 1613 o *added*: "AddedItem[]" The id and index in the query results (in 1614 the new state) for every foo that has been added to the results 1615 since the old state AND every foo in the current results that was 1616 included in the _removed_ array (due to a filter or sort based 1617 upon a mutable property). If the sort and filter are both only on 1618 immutable properties and an _upToId_ is supplied and exists in the 1619 results, any ids that were added but have a higher index than 1620 _upToId_ SHOULD be omitted. The array MUST be sorted in order of 1621 index, lowest index first. An *AddedItem* object has the 1622 following properties: 1624 * *id*: "String" 1626 * *index*: "Number" 1628 The result of this is that if the client has a cached sparse array of 1629 foo ids in the results in the old state: 1631 fooIds = [ "id1", "id2", null, null, "id3", "id4", null, null, null ] 1633 then if it *splices out* all foos in the removed array: 1635 removed = [ "id2", ... ]; 1636 fooIds => [ "id1", null, null, "id3", "id4", null, null, null ] 1638 and *splices in* (in order) all of the foos in the added array: 1640 added = [{ id: "id5", index: 0, ... }]; 1641 fooIds => [ "id5", "id1", null, null, "id3", "id4", null, null, null ] 1643 and *truncates* or *extends* to the new total length, then the 1644 results will now be in the new state. 1646 The following additional errors may be returned instead of the _Foo/ 1647 queryChanges_ response: 1649 "tooManyChanges": There are more changes than the client's 1650 _maxChanges_ argument. Each item in the removed or added array is 1651 considered as one change. The client may retry with a higher max 1652 changes or invalidate its cache of the query results. 1654 "cannotCalculateChanges": The server cannot calculate the changes 1655 from the queryState string given by the client. Usually due to the 1656 client's state being too old. The client MUST invalidate its cache 1657 of the query results. 1659 4.6. Examples 1661 Suppose we have a type _Todo_ with the following properties: 1663 o *id*: "String" (immutable; server-set) The id of the object. 1665 o *title*: "String" A brief summary of what is to be done. 1667 o *keywords*: "String[Boolean]" (mutable; default: "{}") A set of 1668 keywords that apply to the todo. The set is represented as an 1669 object, with the keys being the _keywords_. The value for each key 1670 in the object MUST be "true". 1672 o *neuralNetworkTimeEstimation*: "Number" (server-set) The title and 1673 keywords are fed into the server's state-of-the-art neural network 1674 to get an estimation of how long this todo will take, in seconds. 1676 and the server supports querying by keyword using the syntax "{ 1677 hasKeyword: "foo" }" in the _filter_ argument to _/query_. 1679 Now, a client might want to display the list of todos with a 1680 particular query, so it makes the following method call: 1682 [["Todo/query", { 1683 "filter": { "hasKeyword": "music" }, 1684 "sort": [{ "property": "title" }], 1685 "position": 0, 1686 "limit": 10 1687 }, "0"], 1688 ["Todo/get", { 1689 "#ids": { 1690 "resultOf": "0", 1691 "name": "Todo/query", 1692 "path": "/ids" 1693 }, 1694 }, "1"]] 1696 This would query the server for the set of todos with a keyword of 1697 "music", sorted by title, and limited to the first 10 results. It 1698 fetches the full object for each of these Todos using backreferences 1699 to reference the result of the query. The response might look 1700 something like: 1702 [["Todo/query", { 1703 "accountId": "x", 1704 "filter": { "hasKeyword": "music" }, 1705 "sort": [{ "property": "title" }], 1706 "queryState": "y13213", 1707 "canCalculateChanges": true, 1708 "position": 0, 1709 "total": 26, 1710 "ids": [ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" ] 1711 }, "0"], 1712 ["Todo/get", { 1713 "accountId": "x", 1714 "state": "10324", 1715 "list": [{ 1716 "id": "a", 1717 "title": "Practise Piano", 1718 "keywords": { 1719 "music": true, 1720 "beethoven": true, 1721 "mozart": true, 1722 "liszt": true, 1723 "rachmaninov": true 1724 }, 1725 "neuralNetworkTimeEstimation": 3600 1726 }, { 1727 "id": "b", 1728 "title": "Listen to Daft Punk", 1729 "keywords": { 1730 "music": true, 1731 "trance": true 1732 }, 1733 "neuralNetworkTimeEstimation": 18000 1734 }, 1735 ... 1736 ] 1737 }, "1"]] 1739 Now suppose the user adds a keyword "chopin" and removes the keyword 1740 "mozart" from the "Practise Piano" task. The client may send the 1741 whole object to the server, as this is a valid PatchObject: 1743 [["Todo/set", { 1744 "ifInState": "10324", 1745 "update": { 1746 "a": { 1747 "id": "a", 1748 "title": "Practise Piano", 1749 "keywords": { 1750 "music": true, 1751 "beethoven": true, 1752 "chopin": true, 1753 "liszt": true, 1754 "rachmaninov": true, 1755 } 1756 "neuralNetworkTimeEstimation": 360 1757 } 1758 } 1759 }, "0"]] 1761 or it may send a minimal patch: 1763 [["Todo/set", { 1764 "ifInState": "10324", 1765 "update": { 1766 "a": { 1767 "keywords/chopin": true, 1768 "keywords/mozart": null 1769 } 1770 } 1771 }, "0"]] 1773 The effect is exactly the same on the server in either case, and 1774 presuming the server is still in state "10324" it will probably 1775 return success: 1777 [["Todo/set", { 1778 "accountId": "x", 1779 "oldState": "10324", 1780 "newState": "10329", 1781 "updated": { 1782 "a": { 1783 "neuralNetworkTimeEstimation": 5400 1784 } 1785 } 1786 }, "0"]] 1788 The server changed the "neuralNetworkTimeEstimation" property on the 1789 object as part of this change; as this changed in a way _not_ 1790 explicitly requested by the PatchObject sent to the server, it is 1791 returned with the "updated" confirmation. 1793 Now, suppose another user deleted the "Listen to Daft Punk" todo. 1794 The first user will receive a push notification (see later in the 1795 spec) with the changed state string for the "Todo" type. Since the 1796 new string does not match its current state, it knows it needs to 1797 check for updates. It may make a request like: 1799 [["Todo/changes", { 1800 "accountId": "x", 1801 "sinceState": "10324", 1802 "maxChanges": 50, 1803 }, "0"], 1804 ["Todo/queryChanges", { 1805 "filter": { "hasKeyword": "music" }, 1806 "sort": [{ "property": "title" }], 1807 "sinceQueryState": "y13213" 1808 "maxChanges": 50, 1809 }, "1"]] 1811 and receive in response: 1813 [["Todo/changes", { 1814 "accountId": "x", 1815 "oldState": "10324", 1816 "newState": "871903", 1817 "hasMoreChanges": false, 1818 "created": [], 1819 "updated": [], 1820 "destroyed": ["b"] 1821 }, "0"], 1822 ["Todo/queryChanges", { 1823 "filter": { "hasKeyword": "music" }, 1824 "sort": [{ "property": "title" }], 1825 "oldQueryState": "y13213" 1826 "newQueryState": "y13218" 1827 "total": 25, 1828 "removed": ["b"], 1829 "added": null 1830 }, "1"]] 1832 5. Binary data 1834 Binary data is referenced by a _blobId_ in JMAP, and uploaded/ 1835 downloaded separately to the core API. A blobId does not have a name 1836 inherent to it, but this is normally given in the same object that 1837 contains the blobId. The data represented by a blobId is immutable. 1839 Any blobId that exists within an account may be used when creating/ 1840 updating another object in that account. For example, an Email type 1841 may have a blobId that represents the [RFC5322] representation of the 1842 message. A client could create a new Email object with an attachment 1843 and use this blobId, in effect attaching the old message to the new 1844 one. Similarly it could attach any existing existing attachment of 1845 an old message without having to download and upload it again. 1847 When the client uses a blobId in a create/update, the server MAY 1848 assign a new blobId to refer to the same binary data from the new/ 1849 updated object. If it does so, it MUST return any properties that 1850 contain a changed blobId in the created/updated response so the 1851 client gets the new ids. 1853 A blob that is not referenced by a JMAP object (e.g. as a message 1854 attachment) MAY be deleted by the server to free up resources. 1855 Uploads (see below) are initially unreferenced blobs. To ensure 1856 interoperability: 1858 o The server SHOULD use a separate quota for unreferenced blobs to 1859 the user's usual quota. 1861 o This quota SHOULD be at least the maximum total size that a single 1862 object can reference on this server. For example, if supporting 1863 JMAP Mail, this should be at least the maximum total attachments 1864 size for a message. 1866 o When an upload would take the user over quota, the server MUST 1867 delete unreferenced blobs in date order, oldest first, until there 1868 is room for the new blob. 1870 o Except where quota restrictions force early deletion, an 1871 unreferenced blob MUST NOT be deleted for at least 1 hour from the 1872 time of upload; if reuploaded, the same blobId MAY be returned, 1873 but this SHOULD reset the expiry time. 1875 o A blob MUST NOT be deleted during the method call which removed 1876 the last reference, so that a client can issue a create and a 1877 destroy that both reference the blob within the same method call. 1879 5.1. Uploading binary data 1881 There is a single endpoint which handles all file uploads for an 1882 account, regardless of what they are to be used for. The JMAP 1883 Session object has an _uploadUrl_ property in [RFC6570] URI Template 1884 (level 1) format, which MAY contain a variable called "accountId". 1885 The client may use this template in combination with an _accountId_ 1886 (if required in the template) to get the URL of the file upload 1887 resource. 1889 To upload a file, the client submits an authenticated POST request to 1890 the file upload resource. 1892 A successful request MUST return a single JSON object with the 1893 following properties as the response: 1895 o *accountId*: "String" The id of the account used for the call. 1897 o *blobId*: "String", The id representing the binary data uploaded. 1898 The data for this id is immutable. The id _only_ refers to the 1899 binary data, not any metadata. 1901 o *type*: "String" The media type of the file (as specified in 1902 [RFC6838], section 4.2) as set in the Content-Type header of the 1903 upload HTTP request. 1905 o *size*: "Number" The size of the file in octets. 1907 If identical binary content to an existing blob in the account is 1908 uploaded, the existing blobId MAY be returned. 1910 5.2. Downloading binary data 1912 The JMAP Session object has a _downloadUrl_ property, which is in 1913 [RFC6570] URI Template (level 1) format. The URL MUST contain a 1914 variable called "blobId", MAY contain a variable called "accountId", 1915 and SHOULD contain a variable called "name". 1917 The client may use this template in combination with an _accountId_ 1918 (if required in the URL template) and _blobId_ to download any binary 1919 data (files) referenced by other objects. Since a blob is not 1920 associated with a particular name, the template SHOULD allow a name 1921 to be substituted in as well; the server will return this as the 1922 filename if it sets a "Content-Disposition" header. 1924 To download the data the client makes an authenticated GET request to 1925 the download URL with the appropriate variables substituted in. The 1926 client SHOULD send an "Accept" header with the content type they 1927 would like the server to return for the file. The "Content-Type" 1928 header of a successful response SHOULD be set to the type as 1929 requested in the "Accept" header by the client, or "application/ 1930 octet-stream" if unknown and no "Accept" header given. 1932 5.3. Blob/copy 1934 Binary data may be copied *between* two different accounts using the 1935 _Blob/copy_ method, rather than having to download then reupload on 1936 the client. 1938 The _Blob/copy_ method takes the following arguments: 1940 o *fromAccountId*: "String|null" The id of the account to copy blobs 1941 from. If "null", defaults to the primary account. 1943 o *toAccountId*: "String|null" The id of the account to copy blobs 1944 to. If "null", defaults to the primary account. 1946 o *blobIds*: "String[]" A list of ids of blobs to copy to the other 1947 account. 1949 The response has the following arguments: 1951 o *fromAccountId*: "String" The id of the account emails were copied 1952 from. 1954 o *toAccountId*: "String" The id of the account emails were copied 1955 to. 1957 o *copied*: "String[String]|null" A map of the blob id in the 1958 _fromAccount_ to the id for the blob in the _toAccount_, or "null" 1959 if none were successfully copied. 1961 o *notCopied*: "String[SetError]|null" A map of blob id to a 1962 SetError object for each blob that failed to be copied, "null" if 1963 none. 1965 The *SetError* may be any of the standard set errors that may be 1966 returned for a _create_. 1968 The following additional errors may be returned instead of the _Blob/ 1969 copy_ response: 1971 "fromAccountNotFound": A _fromAccountId_ was explicitly included with 1972 the request, but it does not correspond to a valid account. 1974 "toAccountNotFound": A _toAccountId_ was explicitly included with the 1975 request, but it does not correspond to a valid account. 1977 6. Push 1979 Push notifications allow clients to efficiently update (almost) 1980 instantly to stay in sync with data changes on the server. In JMAP, 1981 push notifications occur out-of-band (i.e. not over the same 1982 connection as API exchanges), so that they can make use of efficient 1983 native push mechanisms on different platforms. 1985 The general model for push is simple and sends minimal data over the 1986 push channel. The format allows multiple changes to be coalesced 1987 into a single push update, and the frequency of pushes to be rate 1988 limited by the server. It doesn't matter if some push events are 1989 dropped before they reach the client; it will still get all changes 1990 next time it syncs. 1992 6.1. The StateChange object 1994 When something changes on the server, the server pushes a 1995 *StateChange* object to the client. A *StateChange* object has the 1996 following properties: 1998 o *changed*: "String[TypeState]" A map of _account id_ to an object 1999 encoding the state of data types that have changed for that 2000 account since the last push event, for each of the accounts to 2001 which the user has access and for which something has changed. A 2002 *TypeState* object is a map. The keys are the type name "Foo" 2003 (e.g. "Mailbox" or "Email"), and the value is the _state_ 2004 property that would currently be returned by a call to _Foo/get_. 2005 The client can compare the new state strings with its current 2006 values to see whether it has the current data for these types. If 2007 not, the changes can then be efficiently fetched in a single 2008 standard API request (using the _/changes_ type methods). 2010 6.2. PushSubscription 2012 A push subscription is a message delivery context established between 2013 the client and a push service. A *PushSubscription* object has the 2014 following properties: 2016 o *url*: "String" An absolute URL where the JMAP server will POST 2017 the data for the push message. This MUST begin with "https://". 2019 o *expires*: "UTCDate|null" The time this push subscription expires. 2020 If specified, the JMAP server MUST NOT make further requests to 2021 this resource after this time. It MAY automatically remove the 2022 push subscription at or after this time. 2024 o *keys*: "Object|null" Client-generated encryption keys. If 2025 supplied the server MUST use them as specified in [RFC8291] to 2026 encrypt all data sent to the push subscription. The object MUST 2027 have the following properties: 2029 * *p256dh*: the P-256 ECDH Diffie-Hellman public key as described 2030 in [RFC8291], encoded in URL-safe base64 representation as 2031 defined in [RFC4648]. 2033 * *auth*: the authentication secret as described in [RFC8291], 2034 encoded in URL-safe base64 representation as defined in 2035 [RFC4648]. 2037 o *types*: "String[]|null" A list of types the client is interested 2038 in (using the same names as the keys in the _TypeState_ object). 2039 Push events will only be sent if the data for one of these types 2040 changes. Other types are omitted from the TypeState object. If 2041 "null", changes will be pushed for all types. 2043 Clients may register the push subscription with the JMAP server, 2044 which will then make a POST request to the associated push endpoint 2045 whenever an event occurs. 2047 The POST request MUST have a content type of "application/json" and 2048 contain the UTF-8 JSON encoded _StateChange_ object as the body. The 2049 request MUST have a "TTL" header, and MAY have "Urgency" and/or 2050 "Topic" headers, as specified in section 5 of [RFC8030]. 2052 If the response code is "503" (Service Unavailable), the JMAP server 2053 MAY try again later, but may also just drop the event. If the 2054 response code is "429" (Too Many Requests) the JMAP server SHOULD 2055 attempt to reduce the frequency of pushes to that URL. Any other 2056 "4xx" or "5xx" response code MUST be considered a *permanent failure* 2057 and the push subscription should be deregistered (not tried again 2058 even for future events unless explicitly re-registered by the 2059 client). 2061 The use of this push endpoint conforms with the use of a push 2062 endpoint by an Application Server as defined in [RFC8030]. A client 2063 MAY use the rest of [RFC8030] in combination with its own Push Server 2064 to form a complete end-to-end solution, or MAY rely on alternative 2065 mechanisms to ensure the delivery of the pushed data after it leaves 2066 the JMAP server. 2068 6.2.1. PushSubscription/set 2070 Each session may only have a single push subscription registered. 2071 The push subscription is tied to the access token used to create it. 2072 Should the access token expire or be revoked, the push subscription 2073 MUST be removed by the JMAP server. The client MUST re-register the 2074 push subscription after reauthenticating to resume callbacks. 2076 To set the push subscription, make a call to _PushSubscription/set_. 2077 It takes the following argument: 2079 o *pushSubscription*: "PushSubscription|null" The PushSubscription 2080 object representing the endpoint the JMAP server will POST events 2081 to. This will replace any previously set subscription. Set to 2082 "null" to remove any previously registered subscription. 2084 The response has no arguments. 2086 The following additional errors may be returned instead of the 2087 _PushSubscription/set_ response: 2089 "invalidUrl": Returned if the URL does not begin with "https://", or 2090 is otherwise syntactically invalid or does not resolve. 2092 "forbidden": Returned if the URL is valid, but for policy reasons the 2093 server is not willing to connect to it. 2095 6.2.2. PushSubscription/get 2097 To check the currently set push subscription (if any), make a call to 2098 _PushSubscription/set_. It does not take any arguments. The response 2099 has a single argument: 2101 o *pushSubscription*: "PushSubscription|null" The PushSubscription 2102 object the JMAP server is currently posting push events to, or 2103 "null" if none. 2105 6.3. Event Source 2107 Clients that can hold open TCP connections can connect directly to 2108 the JMAP server to receive push notifications via a "text/event- 2109 stream" resource, as described in . This is a long running HTTP request down which the 2111 server can push data. 2113 When a change occurs in the data on the server, it pushes an event 2114 called *state* to any connected clients, with the _StateChange_ 2115 object as the data. 2117 The server SHOULD also send a new event id that encodes the entire 2118 server state visible to the user immediately after sending a _state_ 2119 event. When a new connection is made to the event-source endpoint, a 2120 client following the server-sent events specification [1] will send a 2121 Last-Event-ID HTTP header with the last id it saw, which the server 2122 can use to work out whether the client has missed some changes. If 2123 so, it SHOULD send these changes immediately on connection. 2125 The client MAY add a query parameter called "types", with the value 2126 being a comma-separated list of type names. If present, the server 2127 MUST only push changes for the types in this list. If omitted, 2128 changes to all types are pushed. 2130 The client MAY add a query parameter called "closeafter" with value 2131 "state" to the event-source resource URL when requesting the event- 2132 source resource. If set, the server MUST end the HTTP response after 2133 pushing a _state_ event. This can be used by clients in environments 2134 where buffering proxies prevent the pushed data from arriving 2135 immediately, or indeed at all, when operating in the usual mode. 2137 The client MAY add a query parameter called "ping", with a positive 2138 integer value representing a length of time in seconds, e.g. 2139 "ping=300". If set, the server MUST send an event called *ping* 2140 whenever this time elapses since the previous event was sent. This 2141 MUST NOT set a new event id. 2143 The server MAY modify the interval given as a query parameter to be 2144 subject to a minimum and/or maximum value. For interoperability, 2145 servers MUST NOT have a minimum allowed value higher than 30 or a 2146 maximum allowed value less than 300. 2148 The data for the ping event MUST be a JSON object containing an 2149 _interval_ property, the value (type "Number") being the interval in 2150 seconds the server is using to send pings (this may be different to 2151 the requested value if the server clamped it to be within a min/max 2152 value). 2154 Clients can monitor for the _ping_ event to help determine when the 2155 closeafter mode may be required. 2157 Refer to the JMAP Session resource section of this spec for details 2158 on how to get the URL for the event-source resource. Requests to the 2159 resource MUST be authenticated. 2161 A client MAY hold open multiple connections to the event-source 2162 resource, although it SHOULD try to use a single connection for 2163 efficiency. 2165 7. Security considerations 2167 7.1. Transport confidentiality 2169 All HTTP requests MUST use [RFC5246] TLS (https) transport to ensure 2170 the confidentiality of data sent and received via JMAP. Clients MUST 2171 validate TLS certificate chains to protect against man-in-the-middle 2172 attacks. 2174 7.2. Authentication scheme 2176 A number of HTTP authentication schemes have been standardised 2177 (). Servers should take care to assess the security 2179 characteristics of different schemes in relation to their needs when 2180 deciding what to implement. 2182 If offering the Basic authentication scheme, services are strongly 2183 recommended to not allow a user's regular password but require 2184 generation of a unique "app password" via some external mechanism for 2185 each client they wish to connect. This allows connections from 2186 different devices to be differentiated by the server, and access to 2187 be individually revoked. 2189 7.3. Service autodiscovery 2191 Unless secured by something like DNSSEC, autodiscovery of server 2192 details is vulnerable to a DNS poisoning attack leading to the client 2193 talking to an attacker's server instead of the real JMAP server. The 2194 attacker may then man-in-the-middle requests and depending on the 2195 authentication scheme, steal credentials to generate its own 2196 requests. 2198 Clients that do not support SRV lookups are likely to try just using 2199 the "/.well-known/jmap" path directly against the domain of the 2200 username over HTTPS. Servers SHOULD ensure this path resolves or 2201 redirects to the correct JMAP Session resource to allow this to work. 2202 If this is not feasible, servers MUST ensure this path cannot be 2203 controlled by an attacker, as again it may be used to steal 2204 credentials. 2206 7.4. JSON parsing 2208 The security considerations of [RFC7159] apply to the use of JSON as 2209 the data interchange format. 2211 7.5. Denial of service 2213 A small request may result in a very large response, and require 2214 considerable work on the server if resource limits are not enforced. 2215 JMAP provides mechanisms for advertising and enforcing a wide variety 2216 of limits for mitigating this threat, including limits on number of 2217 objects fetched in a single method call, number of methods in a 2218 single request, number of concurrent requests, etc. 2220 JMAP servers MUST implement sensible limits to mitigate against 2221 resource exhaustion attacks. 2223 7.6. Push encryption 2225 When data changes, a small object is pushed with the new state 2226 strings for the types that have changed. While the data here is 2227 minimal, a passive man-in-the-middle attacker may be able to gain 2228 useful information. To ensure confidentiality, if the push is sent 2229 via a third party outside of the control of the client and JMAP 2230 server the client MUST specify encryption keys when establishing the 2231 PushSubscription. 2233 The privacy and security considerations of [RFC8030] and [RFC8291] 2234 also all apply to the use of the PushSubscription mechanism. 2236 8. IANA Considerations 2238 8.1. Assignment of jmap Service Name 2240 IANA will assign the 'jmap' service name in the 'Service Name and 2241 Transport Protocol Port Number Registry' [RFC6335]. 2243 Service Name: jmap 2245 Transport Protocol(s): tcp 2247 Assignee: IESG 2249 Contact: IETF Chair 2251 Description: JSON Meta Application Protocol 2253 Reference: this document 2255 Assignment Notes: this service name was previously assigned under the 2256 name _JSON Mail Access Protocol_. This will be de-assigned and re- 2257 assigned with the approval of the previous assignee. 2259 8.2. Registration of Well-known URI suffix for JMAP 2261 IANA will register the following well-known URI suffix for JMAP as 2262 described in [RFC5785]: 2264 URI Suffix: jmap 2266 Change Controller: IETF 2268 Specification Document: this document, section 2.1. 2270 8.3. Registration of the jmap URN Sub-namespace 2272 IANA will register the following URN sub-namespace in the "IETF URN 2273 Sub-namespace for Registered Protocol Parameter Identifiers" registry 2274 as described in [RFC3553]. 2276 Registered Parameter Identifier: jmap 2278 Reference: this document, next section 2280 IANA Registry Reference: {insert IANA registry URL for registry in 2281 next section, upon approval} 2283 8.4. Creation of "JMAP capabilities" registry 2285 IANA will create a registry for JMAP capabilities as described in 2286 section 2.1. JMAP capabilities are advertised in the _capabilities_ 2287 property of the _JMAP Session_ resource. They are used to extend the 2288 functionality of a JMAP server. A capability is referenced by a URI. 2289 The JMAP capability URI can be a URN starting with 2290 "urn:ietf:params:jmap:" plus a unique suffix which is the index value 2291 in the jmap URN sub-namespace. Registration of a JMAP capability 2292 with another form of URI has no impact on the jmap URN sub-namespace. 2294 This registry follows the expert review process unless the "intended 2295 use" field is _common_ in which case registration follows the 2296 specification required process. 2298 A JMAP capability registration can have an intended use of 'common', 2299 'limited', or 'obsolete'. IANA will list common use registrations 2300 prominently and separately from those with other intended use values. 2302 The JMAP capability registration procedure is not a formal standards 2303 process, but rather an administrative procedure intended to allow 2304 community comment and sanity checking without excessive time delay. 2306 8.4.1. Preliminary Community Review 2308 Notice of a potential JMAP common use registration SHOULD be sent to 2309 the jmap@ietf.org mailing list for review. This mailing list is 2310 appropriate to solicit community feedback on a proposed JMAP 2311 capability. Registrations that are not intended for common use MAY 2312 be sent to the list for review as well; doing so is entirely 2313 OPTIONAL, but is encouraged. 2315 The intent of the public posting to this list is to solicit comments 2316 and feedback on the choice of capability name, the unambiguity of the 2317 specification document, and a review of any interoperability or 2318 security considerations. The submitter may submit a revised 2319 registration proposal or abandon the registration completely and at 2320 any time. 2322 8.4.2. Submit Request to IANA 2324 Registration requests can be sent to iana@iana.org. 2326 8.4.3. Designated Expert Review 2328 For a limited use registration, the designated expert's (DE) primary 2329 concern is preventing name collisions and encouraging the submitter 2330 to document security and privacy considerations; a published 2331 specification is not required. For a common use registration, the DE 2332 is expected to confirm that suitable documentation as described in 2333 [RFC8126], Section 4.6, is available. The DE should also verify the 2334 capability does not conflict with work that is active or already 2335 published within the IETF. 2337 Before a period of 30 days has passed, the DE will either approve or 2338 deny the registration request and publish a notice of the decision to 2339 the JMAP WG mailing list or its successor, as well as informing IANA. 2340 A denial notice must be justified by an explanation, and in the cases 2341 where it is possible, concrete suggestions on how the request can be 2342 modified so as to become acceptable should be provided. 2344 8.4.4. Change Procedures 2346 Once a JMAP capability has been published by the IANA, the change 2347 controller may request a change to its definition. The same 2348 procedure that would be appropriate for the original registration 2349 request is used to process a change request. 2351 JMAP capability registrations may not be deleted; capabilities that 2352 are no longer believed appropriate for use can be declared obsolete 2353 by a change to their "intended use" field; such capabilities will be 2354 clearly marked in the lists published by the IANA. 2356 Significant changes to a capability's definition should be requested 2357 only when there are serious omissions or errors in the published 2358 specification. When review is required, a change request may be 2359 denied if it renders entities that were valid under the previous 2360 definition invalid under the new definition. 2362 The owner of a JMAP capability may pass responsibility to another 2363 person or agency by informing the IANA; this can be done without 2364 discussion or review. 2366 The IESG may reassign responsibility for a JMAP capability. The most 2367 common case of this will be to enable changes to be made to 2368 capabilities where the author of the registration has died, moved out 2369 of contact, or is otherwise unable to make changes that are important 2370 to the community. 2372 8.4.5. JMAP Capabilities Registry Template: 2374 Capability name: (see capability property in section 2) 2376 Specification document: 2378 Intended use: (one of common, limited, or obsolete) 2380 Change controller: (_IETF_ for standards-track/BCP RFCs) 2382 Security and privacy considerations: 2384 8.4.6. Initial Registration 2386 Capability Name: "urn:ietf:params:jmap:core" 2388 Specification document: this document, section 2 2390 Intended use: common 2392 Change Controller: IETF 2394 Security and privacy considerations: this document, section 7. 2396 9. References 2397 9.1. Normative References 2399 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 2400 Requirement Levels", BCP 14, RFC 2119, 2401 DOI 10.17487/RFC2119, March 1997, 2402 . 2404 [RFC2782] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for 2405 specifying the location of services (DNS SRV)", RFC 2782, 2406 DOI 10.17487/RFC2782, February 2000, 2407 . 2409 [RFC3339] Klyne, G. and C. Newman, "Date and Time on the Internet: 2410 Timestamps", RFC 3339, DOI 10.17487/RFC3339, July 2002, 2411 . 2413 [RFC3553] Mealling, M., Masinter, L., Hardie, T., and G. Klyne, "An 2414 IETF URN Sub-namespace for Registered Protocol 2415 Parameters", BCP 73, RFC 3553, DOI 10.17487/RFC3553, June 2416 2003, . 2418 [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO 2419 10646", STD 63, RFC 3629, DOI 10.17487/RFC3629, November 2420 2003, . 2422 [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data 2423 Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006, 2424 . 2426 [RFC4790] Newman, C., Duerst, M., and A. Gulbrandsen, "Internet 2427 Application Protocol Collation Registry", RFC 4790, 2428 DOI 10.17487/RFC4790, March 2007, 2429 . 2431 [RFC5051] Crispin, M., "i;unicode-casemap - Simple Unicode Collation 2432 Algorithm", RFC 5051, DOI 10.17487/RFC5051, October 2007, 2433 . 2435 [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security 2436 (TLS) Protocol Version 1.2", RFC 5246, 2437 DOI 10.17487/RFC5246, August 2008, 2438 . 2440 [RFC5322] Resnick, P., Ed., "Internet Message Format", RFC 5322, 2441 DOI 10.17487/RFC5322, October 2008, 2442 . 2444 [RFC5785] Nottingham, M. and E. Hammer-Lahav, "Defining Well-Known 2445 Uniform Resource Identifiers (URIs)", RFC 5785, 2446 DOI 10.17487/RFC5785, April 2010, 2447 . 2449 [RFC6186] Daboo, C., "Use of SRV Records for Locating Email 2450 Submission/Access Services", RFC 6186, 2451 DOI 10.17487/RFC6186, March 2011, 2452 . 2454 [RFC6335] Cotton, M., Eggert, L., Touch, J., Westerlund, M., and S. 2455 Cheshire, "Internet Assigned Numbers Authority (IANA) 2456 Procedures for the Management of the Service Name and 2457 Transport Protocol Port Number Registry", BCP 165, 2458 RFC 6335, DOI 10.17487/RFC6335, August 2011, 2459 . 2461 [RFC6570] Gregorio, J., Fielding, R., Hadley, M., Nottingham, M., 2462 and D. Orchard, "URI Template", RFC 6570, 2463 DOI 10.17487/RFC6570, March 2012, 2464 . 2466 [RFC6764] Daboo, C., "Locating Services for Calendaring Extensions 2467 to WebDAV (CalDAV) and vCard Extensions to WebDAV 2468 (CardDAV)", RFC 6764, DOI 10.17487/RFC6764, February 2013, 2469 . 2471 [RFC6838] Freed, N., Klensin, J., and T. Hansen, "Media Type 2472 Specifications and Registration Procedures", BCP 13, 2473 RFC 6838, DOI 10.17487/RFC6838, January 2013, 2474 . 2476 [RFC6901] Bryan, P., Ed., Zyp, K., and M. Nottingham, Ed., 2477 "JavaScript Object Notation (JSON) Pointer", RFC 6901, 2478 DOI 10.17487/RFC6901, April 2013, 2479 . 2481 [RFC7159] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data 2482 Interchange Format", RFC 7159, DOI 10.17487/RFC7159, March 2483 2014, . 2485 [RFC7230] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer 2486 Protocol (HTTP/1.1): Message Syntax and Routing", 2487 RFC 7230, DOI 10.17487/RFC7230, June 2014, 2488 . 2490 [RFC7235] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer 2491 Protocol (HTTP/1.1): Authentication", RFC 7235, 2492 DOI 10.17487/RFC7235, June 2014, 2493 . 2495 [RFC7493] Bray, T., Ed., "The I-JSON Message Format", RFC 7493, 2496 DOI 10.17487/RFC7493, March 2015, 2497 . 2499 [RFC7807] Nottingham, M. and E. Wilde, "Problem Details for HTTP 2500 APIs", RFC 7807, DOI 10.17487/RFC7807, March 2016, 2501 . 2503 [RFC8030] Thomson, M., Damaggio, E., and B. Raymor, Ed., "Generic 2504 Event Delivery Using HTTP Push", RFC 8030, 2505 DOI 10.17487/RFC8030, December 2016, 2506 . 2508 [RFC8126] Cotton, M., Leiba, B., and T. Narten, "Guidelines for 2509 Writing an IANA Considerations Section in RFCs", BCP 26, 2510 RFC 8126, DOI 10.17487/RFC8126, June 2017, 2511 . 2513 [RFC8291] Thomson, M., "Message Encryption for Web Push", RFC 8291, 2514 DOI 10.17487/RFC8291, November 2017, 2515 . 2517 9.2. URIs 2519 [1] https://html.spec.whatwg.org/multipage/server-sent-events.html 2521 Author's Address 2523 Neil Jenkins 2524 FastMail 2525 PO Box 234, Collins St West 2526 Melbourne VIC 8007 2527 Australia 2529 Email: neilj@fastmailteam.com 2530 URI: https://www.fastmail.com