Skip to content

Rest.li 2.0 Proposed Changes

karanparikh edited this page Nov 11, 2014 · 8 revisions

NOTE - Any time there is a difference between Rest.li protocol 1.0 and Rest.li protocol 2.0 it will be explicitly mentioned. If nothing is said that means that there is no difference.

h2. URI Syntax

URIs are described using URI templates as defined in the "IETF Draft Spec":http://tools.ietf.org/html/draft-gregorio-uritemplate-07.

h2. On-line documentation

Rest.li provides "on-line documentation":https://github.com/linkedin/rest.li/wiki/Rest.li-User-Guide#on-line-documentation for any loaded resource. The documentation shows example request and response for the resource methods, finders and actions. Please use it to help understanding the Rest.li protocols.

h2. Content Types

The content types of Rest.li data are @application/json@ and @application/pson@. @pson@ is a compressed version of json.

h2. Rest.li 2.0 Protocol Object Notation

In order to simplify the String serialized representation of compound (also known as association) and complex types, as well as to make the representations consistent with each other, the Rest.li 2.0 protocol introduces a new object notation for compound and complex types.

Compound and complex types have a similar structure: they are essentially a collection of key-value pairs. In other words, they are a map. In both cases the keys are always strings. In compound types the values are primitives (strings, ints, etc.). In complex types the values are primitives, or arrays, or a map.

h3. URL Representation

In Rest.li 2.0, the way to represent a complex or compound type in the URL is using key:value pairs. More concretely -


(urlEncoded(k1):encoded(v1),urlEncoded(k2):encoded(v2),...)

Since the keys are strings all we need to do is URL encode them.

h4. Encoding the values in the URL

Based on the value, encoded is defined as follows -

  • the value is a primitive: we simply URL encode the value.
  • the value is a map: we encode the map using the Rest.li 2.0 protocol object notation.
  • the value is an array: we encode the array using the List notation described below.

h3. HTTP body representation

In general, keys and values do not have to be URL encoded when present in the HTTP body. However, since ,, (, ), and : are special Rest.li characters those must be URL encoded.

h2. Rest.li 2.0 Protocol Array Notation

h3. URL Representation

An array [a1, a2, a3, ...] is encoded in the URL as -


List(encoded(a1),encoded(a2),encoded(a3),...)

Based on the value, encoded is defined as follows -

  • the value is a primitive: we simply URL encode the value.
  • the value is a map: we encode the map using the Rest.li 2.0 protocol object notation described above.
  • the value is an array: we encode the array using the List notation.

h3. HTTP body representation

In general, values do not have to be URL encoded when present in the HTTP body. However, since ,, (, and ) are special Rest.li characters those must be URL encoded.

h2. Collection Resources

The URI templates below assume variables with types as follows:


collection : simple string or "complex key"
entity_id : simple string
ids : list
finder : simple string
params : associative array

h3. Collection URIs

|. Resource |. URI Template |. Example |. Method |_. Semantics | | Collection | /{collection} | /statuses | POST | CREATE - creates an entity in the collection | | Collection | /{collection}/{entity_id} | /statuses/1 | GET | READ - returns the referenced entity | | Collection | /{collection}/{entity_id} | /statuses/1 | PUT | UPDATE - updates the referenced entity | | Collection | /{collection}/{entity_id} | /statuses/1 | POST | PARTIAL UPDATE - partially updates the referenced entity | | Collection | /{collection}/{entity_id} | /statuses/1 | DELETE | DELETE - deletes the referenced entity | | Collection | /{collection}?{ids} | Protocol 1.0 - /statuses?ids=1&ids=2&ids=3 Protocol 2.0 - /statuses?ids=List(1,2,3) | GET | BATCH_GET - returns a map containing the referenced entities | | Collection | /{collection} | /statuses | GET | GET_ALL - returns all entities in the collection | | Collection | /{collection}?q={finder} | /statuses?q=search | GET | FINDER - returns a list containing entities satisfying the query | | Collection | /{collection}?q={finder}{&params*} | /statuses?q=search&keywords=linkedin | GET | FINDER - returns a list containing entities satisfying the query | | Collection | /{collection}?action={action} | /statuses?action=purge | POST | ACTION - some operation, rest.li does not specify any standard behavior |

h2. Simple Resources

The URI templates below assume variables with types as follows:


simple : simple string
params : associative array

h3. Simple URIs

|. Resource |. URI Template |. Example |. Method |_. Semantics | | Simple | /{simple} | /selectedItem | GET | READ - returns the entity | | Simple | /{simple} | /selectedItem | PUT | UPDATE - updates the entity | | Simple | /{simple} | /selectedItem | DELETE | DELETE - deletes the entity | | Simple | /{simple}?action={action} | /selectedItem?action=investigate | POST | ACTION - some operation, rest.li does not specify any standard behavior |

h2. Association Resources

Associations contain entities referenced by compound keys, referred to here as assockeys

The URI templates below assume variables with types as follows:


firstkey : associative array containing a single element
keys : associative array
association : simple string
assockey : simple string conforming to the assockey syntax described below
assockeys : list of strings conforming to the assockey syntax
finder : simple string
params : associative array

h3. Association Keys

Association keys are composed of one or more named assocKey parts.

In protocol 1.0 the key is represented over the wire in the form:

{firstkey}{&keys*}

In protocol 2.0 the key is represented using the protocol 2.0 object notation, with each assocKey being a key in the map.

For example, a two part key identifying an edge in a following graph in protocol 1.0 might be:

followerID=1&followeeID=3

In protocol 2.0 the key would be

(followerID:1,followeeID:3)

Here's an example association GET request/response. In protocol 1.0:

GET /associations/src=KEY1&desk=KEY2
{
    "message": "Hi!",
    "id": "1"
}

In protocol 2.0:

GET /associations/(src:KEY1,desk:KEY2)
{
    "message": "Hi!",
    "id": "1"
}

In finders, only some keys from the full association key might be required. For example, in protocol 1.0:

followerID=1

In protocol 2.0:

(followerID:1)

All string values for association keys are url encoded. E.g. for the association key composed of code="1=2b" and widget="xyz widget", a GET request in protocol 1.0 using the key would be:

GET /resourceName/code=1%32b&widget=xyz%20widget

In protocol 2.0 it would be:

GET /resourceName/(code:1%32b,widget:xyz%20widget)

When association keys are used in a batch operation, each key is url encoded. For protocol 1.0 the form is:


ids=urlencoded(associationKey1)&ids=urlencoded(associationKey2)...

For protocol 2.0 is ids use the protocol 2.0 array notation.


ids=List((encoded(associationKey1)),(encoded(associationKey2)),...)

For example, in protocol 1.0 a batch get for the keys: src=KEY1&dest=KEY3 and src=KEY1&dest=KEY2, would be:

GET /associations?ids=src%3DKEY1%26dest%3DKEY2&ids=src%3DKEY1%26dest%3DKEY3

{
  "errors": {},
    "results": {
        "dest=KEY3&src=KEY1": {
            "message": "Hi!",
            "id": "1"
        },
        "dest=KEY2&src=KEY1": {
            "message": "Hello!",
            "id": "2"
        }
    }
}

In protocol 2.0 a batch get for the keys: (src:KEY1,dest:KEY3) and (src:KEY1,dest:KEY2), would be:

GET /associations?ids=List((src:KEY1,dest:KEY3),(src:KEY1,dest:KEY2))

{
  "errors": {},
    "results": {
        "(dest:KEY3,src:KEY1)": {
            "message": "Hi!",
            "id": "1"
        },
        "(dest:KEY2,src:KEY1)": {
            "message": "Hello!",
            "id": "2"
        }
    }
}

Here's the basic form of a batch update request using association keys. In protocol 1.0:


PUT /resourceName?ids=urlencoded(key1=urlencoded(value)&key2=urlencoded(value)&...)&ids=...

{
  "entities": {
    "key=urlencoded(value)&key2...": { ... },
    ...
  }
}

Note that in the URL the ids are url encoded AND any strings values for the assocKey parts are double url encoded.

In protocol 2.0 the protocol 2.0 array representation is used for the ids.

For example, for a batch update for the association keys: (code="1=2b", name="xyz widget") and (code="567", name="rachet")

The batch update request in protocol 1.0 would be:


PUT /widgets?ids=code%3D1%2532b%26widget%3Dxyz%2520widget&ids=code%3D567%26widget%3Drachet

{
  "entities": {
     "code=1%32b&name=xyz%20widget": {...},
     "code=567&name=rachet": {...}
  }
}

In protocol 2.0 the request would be:


PUT /widgets?ids=List((code:1%202b,name:xyz%20widget),(code:567,name:rachet))

{
  "entities": {
     "(code:1=2b,name:xyz widget)": {...},
     "(code:567,name:rachet)": {...}
  }
}

h3. Association URIs

|. Resource |. URI Template |. Example |. Method |_. Semantics | | Association | /{association}/{+assockey} | Protocol 1.0 - /follows/followerID=1&followeeID=1 Protocol 2.0 - /follows/(followerID:1,followeeID:1) | GET | READ - returns the referenced association entity | | Association | /{association}/{+assockey} | Protocol 1.0 - /follows/followerID=1&followeeID=1 Protocol 2.0 - /follows/(followerID:1,followeeID:1) | PUT | UPDATE - updates the referenced association entity | | Association | /{association}/{+assockey} | Protocol 1.0 - /follows/followerID=1&followeeID=1 Protocol 2.0 - /follows/(followerID:1,followeeID:1) | DELETE | DELETE - deletes the referenced association entity | | Association | /{association}/{+assockeys*} | Protocol 1.0 - /follows/?ids=followerID%3D1%26followeeID%3D1& ids=followerID%3D1%26followeeID%3D3& ids=followerID%3D1%26followeeID%3D2 \ Note: followerID%3D1%26followeeID%3D1 unescapes to followerID=1&followeeID=1 Protocol 2.0 - /follows/?ids=List((followerID:1,followeeID:1),(followerID:1,followeeID:2)) | GET | BATCH_GET - returns a map containing the referenced association entities | | Association | /{association} | /follows | GET | GET_ALL - returns all the association entities | | Association | /{association}?q={finder} | /follows?q=search | GET | FINDER - returns a list containing entities satisfying the query | | Association | /{association}?q={finder}{&params*} | /follows?q=followers&userID=1 | GET | FINDER - returns a list containing entities satisfying the query | | Association | /{association}/{+assockey} | Protocol 1.0 - /follows/followerID=1?q=other Protocol 2.0 - /follows/(followerID:1)?q=other | GET | FINDER - returns a list containing the entities satisfying the query | | Association | /{association}/{+assockey}?q={finder}{&params*} | Protocol 1.0 - /follows/followerID=1?q=other&someParam=value Protocol 2.0 - /follows/(followerID:1)?q=other&someParam=value | GET | FINDER - returns a list containing the entities satisfying the query | | Association | /{association}?action={action} | /follows?action=purge | POST | ACTION - some operation, rest.li does not specify any standard behavior |

h2. Finders

The URI templates below assume variables with types as follows:


finder : simple string identifying a finder

h3. Finder URIs

|. Resource |. URI Template |. Example |. Method |_. Semantics | | Collection, Association, ActionSet | {resource}?q={finder} | /accounts?q=keywordSearch | GET | invokes the specified finder |

h2. Actions

The URI templates below assume variables with types as follows:


action : simple string

h3. Action URIs

|. Resource |. URI Template |. Example |. Method |_. Semantics | | Collection, Simple, Association, ActionSet | {resource}?action={action} | /accounts?action=register | POST | invokes the specified action |

h2. URI modifiers

The URI templates below assume variables with types as follows:


finder_uri : simple string ...
base_uri : simple string generated via one of the uri templates above
start : simple string
count : simple string
fields : list

h3. URIs

|. Feature |. Base URI Type |. URI Template |. Example | | Paging | Finder | {+finder_uri}{&start,count} | /statuses?q=search&start=0&count=10 | | Projection | Get, BatchGet, Finder | {+base_uri}{&fields} | /groups?q=emailDomain&fields=locale,state | | Schema Return | Any | {+base_uri}&metaDesc | | | Links | Any | {+base_uri}&metaLinks | |

h2. Response Status Codes

Status codes should be interpreted according to the "HTTP specification":http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

Common status codes used in Rest.li:

  • 200 OK
  • 201 Created
  • 204 No Content
  • 400 Bad Request
  • 404 Not Found
  • 405 Method Not Allowed
  • 500 Internal Server Error

h2. Message Headers

|. Message Type |. Header |. Semantics |. Notes | | Response | X-LinkedIn-Error-Response | indicates whether the message body contains a JSON-serialized ErrorResponse object | The header value is set to "true" when an error response is returned. The header is omitted otherwise. Only used in protocol 1.0 | | Response | X-RestLi-Error-Response | indicates whether the message body contains a JSON-serialized ErrorResponse object | The header value is set to "true" when an error response is returned. The header is omitted otherwise. Only used in protocol 2.0 | | Response | X-LinkedIn-Id | indicates the id assigned by the server to a new entity created in a collection. | set on response messages resulting from a successful POST request to create an entity. The header value is set to the entity id, represented as a string. Only used in protocol 1.0 | | Response | X-RestLi-Id | indicates the id assigned by the server to a new entity created in a collection. | set on response messages resulting from a successful POST request to create an entity. The header value is set to the entity id, represented as a string. Only used in protocol 2.0 | | Response | Location | indicates the URI of a new entity created in a collection. | Location is set on response messages resulting from a successful POST request to create an entity. The header value is set to a URI referencing the newly created entity | | Response | Content-Type | | The Content-Type is always set to "application/json" | | Request | X-RestLi-Method | Set whenever content is POSTed. Can be "GET_ALL", "GET", "BATCH_GET", "CREATE", "BATCH_CREATE", "UPDATE", "PARTIAL_UPDATE", "DELETE", "BATCH_DELETE", "ACTION", "FINDER", "BATCH_PARTIAL_UPDATE" | Is only required for "BATCH_CREATE", "BATCH_PARTIAL_UPDATE", all other method types can be inferred by a RestLi server from the URI string and HTTP Method. |

h2. Request Message Body

h3. Single Entity

Single entities are sent as the JSON serialized DataMap representing that entity. The @"Content-Type: application/json"@ header may be included for PUT and POST requests, if omitted, the server will assume the request is content type is @"application/json"@.

Create:


POST /widgets
Content-Type: application/json

{"widgetName":"Lever"}

Read:

for collection and association resources:


GET /widgets/1

for simple resources:


GET /currentWidget

Update:

for collection and association resources:


PUT /widgets/1
Content-Type: application/json

{"widgetName":"Lever"}

for simple resources:


PUT /currentWidget
Content-Type: application/json

{"widgetName":"Lever"}

Delete:

for collection and association resources:


DELETE /widgets/1

for simple resources:


DELETE /currentWidget

h3. Batch Create

A DataMap with field

  • "elements": A JSON array of the resources to batch create/update and the objects are the json serialized values of each resource to create.

E.g.


POST /widgets HTTP/1.1
Content-Type: application/json
X-RestLi-Method: BATCH_CREATE

{
  "elements": [
    {"widgetName":"Ratchet"},
    {"widgetName":"Cog"},
    {"widgetName":"!@&%@$#"}
  ]
}

Response:


{
  "elements": [
    {
      "status": 201,
      "id": "100"
    },
    {
      "status": 201,
      "id": "101"
    },
    {
      "status": 406,
      "error": {
        "status": 406,
        "stackTrace": "...",
        "errorDetails": { ... },
        "serviceErrorCode": 999, 
        "exceptionClass": "...", 
        "message": "..."
      }
  ]
}

Responses are associated to the request by array index. E.g. "Rachet" was assigned id 100, "Cog" was assigned id 101 and "!@&%@$#" resulted on a 406 response code and was not assigned an id.

Note: Batch create requests must include the HTTP Header:

X-RestLi-Method: BATCH_CREATE

h3. Batch Update

A DataMap with field

  • "entities": A JSON serialized map where the keys are keys of the resources to update and the objects are the json serialized replacement values of each resource to update.

E.g.


PUT /widgets?ids=1&ids=2 HTTP/1.1
Content-Type: application/json
X-RestLi-Method: BATCH_UPDATE

{
  "entities": {
    "1": {"widgetName":"Trebuchet"},
    "2": {"widgetName":"Gear"}
   }
}

Response:


{
  "errors": {},
  "results": {
    "1": {
      "status": 204
    },
    "2": {
      "status": 204
    }
  ]
}

h3. Partial Update

Partial update is a set of operations on data object, which is also instance of DataMap. Operations are expressed using fields with reserved word names. Every operation relates to the object that contains it i.e. it's parent. Following sections describe all currently supported operations. See [ENGS:Partial Update] for details.

E.g.


POST /widgets/1 HTTP/1.1
Content-Type: application/json

{
  "patch": {
    "$set": {
      "name": "John",
      "address": {
        "street": "10th",
        "city": "Sunnyvale"
      }
    }
  }
}

h3. Batch Partial Update

See Partial Update and Batch Update above for details, here the two are combined.

E.g.


POST /widgets?ids=1&ids=2 HTTP/1.1
Content-Type: application/json
X-RestLi-Method: BATCH_PARTIAL_UPDATE

{
  "entities": {
    "1": {"patch": { "$set": { "name":"Sam"}}}
    "2": {"patch": { "$delete": ["name"]}}
   }
}

h3. Action

Action params are provided in the request body which must contain a data map keyed by param names. E.g.


POST /widgets?action=purge HTTP/1.1
Content-Type: application/json
{
  "reason": "spam",
  "purgedByAdminId": 1
}

The @X-RestLi-Method: ACTION@ may optionally be included, but is not required because rest.li is able to determine the request is an action based on the "action" query param key.

h2. Response Message Body

h3. Single Entity

Single entities are returned as the JSON serialized DataMap representing that entity

h3. List of Entities

Lists of entities are returned in a com.linkedin.rest.CollectionResponse wrapper. They are returned by finders and getAll.

CollectionResponse fields:

  • "elements" : JSON serialized list of entity types
  • (optional) "paging" : JSON serialized CollectionMetadata object

E.g.


{
  "elements: [
    { "id": 1, "message": "Good morning!", "tone": "FRIENDLY" }
    // ...
  ],
  "metadata" { // only returned by finders that define a metadata schema as part of the interface
    // ...
  },
  "paging": {
    "count": 10,
    "links": [
      "href": "/greetings?count=10&start=10&q=search",
      "rel": "next",
      "type": "application/json"
    ],
    "start": 0
  }
}

h3. Map of Entities

Maps of entities are returned in a com.linkedin.rest.BatchResponse wrapper. BatchResponse is used as the response for BATCH_GET requests.

BatchResponse fields:

  • "results" : JSON object containing name/value pairs ** name is the string value of each map key ** value is the JSON serialized entity for each map value
  • "errors": Errors for

GET /fortunes?ids=1&ids=2&ids=unacceptableKey&ids=faultyKey
{
  "errors": {
     "unacceptableKey": {
       "status": 416,
       "message": "Not Acceptable"
     },
     "faultyKey": {
       "status": 500,
       "exceptionClass": "org.example.SomeServerException",
       "stacktrace": "SomeServerException at org.example.SomeClass.someMethod(SomeClass.java:1)\n..."
     }
   },
  "results": {
    "1": {...},
    "2": {...}
    }
  }
}

h3. Collection Metadata


{"type":"record",
 "name":"CollectionMetadata",
 "namespace":"com.linkedin.common.rest",
 "doc":"Metadata and pagination links for this collection",
 "fields":[
 {
   "name":"start",
   "type":"int",
   "doc":"The start index of this collection"
 },{
   "name":"count",
   "type":"int",
   "doc":"The number of elements in this collection segment"
 },{
   "name":"total",
   "type":"int",
   "doc":"The total number of elements in the entire collection (not just this segment)",
   "default":0
 },{
   "name":"links",
   "type":{
     "type":"array",
     "items":{
       "type":"record",
       "name":"Link",
       "doc":"A atom:link-inspired link",
       "fields":[
       {
         "name":"rel",
         "type":"string",
         "doc":"The link relation e.g. 'self' or 'next'"
       },{
         "name":"href",
         "type":"string",
         "doc":"The link URI"
       },{
         "name":"type",
         "type":"string",
         "doc":"The type (media type) of the resource"
       }]
     }
   },
   "doc":"Previous and next links for this collection"
}]}

h3. Error Response


{
  "type":"record",
  "name":"ErrorResponse",
  "namespace":"com.linkedin.common.rest",
  "doc":"A generic ErrorResponse",
  "fields":[
  {
    "name":"status",
    "type":"int",
    "doc":"The HTTP status code"
  },{
    "name":"serviceErrorCode",
    "type":"int",
    "doc":"An service-specific error code (documented in prose)"
  },{
    "name":"message",
    "type":"string",
    "doc":"A human-readable explanation of the error"
  },{
    "name":"exceptionClass",
    "type":"string",
    "doc":"The FQCN of the exception thrown by the server (included the case of a server fault)"
  },{
    "name":"stackTrace",
    "type":"string",
    "doc":"The full (??) stack trace (included the case of a server fault)"
  }]
}

h3. Action Response

Actions may optionally return a response body. If they do, it must contain a data map with a single "value" key, where the value of the key is either a primitive type, e.g.:


{
  "value": 1
}

or complex data type, e.g.:


{
  "value": {
    "firstName": "John",
    "lastName": "Smith"
  }
}

h2. Complex types

h3. Complex types as keys in protocol 1.0

The serialized form of a complex key uses path keys to specify the values of data elements in a complex data type. For example, given the complex data:


{
  "key": {
    "x": [
      "a1",
      "a2"
    ],
    "y": 123,
    "key.with.dots": "val"
  }
}

Its serialized form is:


// Complex key as a serialized string:
key.x[0]=a1&key.x[1]=a2&key.y=123&key~2Ewith~2Edots=val

If this serialized form is put into a URI (as it usually is), the '[' must be escaped as '%5B' and the ']' must be escaped as '%5D' (URIs require this), so you have the URI form:


// Complex key as a serialized string, escaped for URI:
key.x%5B0%5D=a1&key.x%5B1%5D=a2&key.y=123&key~2Ewith~2Edots=val

Where, in the values of the query params, the chars '.[]' are "~ encoded" to their ascii values. This encoding is the same as "% encoding" except that the escape char is '~' and the only reserved chars are '.[]'.


. -> ~2E
[ -> ~5B
] -> ~5D
~ -> ~7E

The @Params@ of a @ComplexResourceKey@ are always prefixed with "$params." when represented in a URI, e.g.:


$params.x=a1

h3. Complex types as keys in protocol 2.0

The serialized form of a complex key uses the Rest.li 2.0 protocol object notation. For example, given the complex data:


{
  "key": {
    "x": [
      "a1",
      "a2"
    ],
    "y": 123
  }
}

Its serialized form is:


// Complex key as a serialized string:
(key:(x:List(a1,a2)),y:123)

The @Params@ of a @ComplexResourceKey@ are always prefixed with "$params." when represented in a URI, e.g.:


$params:(x:a1)

h3. Complex keys in batch requests in protocol 1.0

If used in batch requests, each key in the batch is represented as a element in an array, the complex data representation is:


[
  {  }, {  }
]

And it's serialized representation is just the list flattened using the same rules as with any complex key, and with the same "~ encoding" applied.

For example,


[
  { "keypart1":"v1", "keypart2":"v2" }, { "keypart1":"v3", "keypart2":"v4" }
]

It's serialized form is:


// Complex key as a serialized string:
ids[0].keypart1=v1&ids[0].keypart2=v2&ids[1].keypart1=v3&ids[1].keypart2=v4

If this serialized form is put into a URI (as it usually is), the '[' must be escaped as '%5B' and the ']' must be escaped as '%5D' (URIs require this), so you have the URI form:


// Complex key as a serialized string, escaped for URI:
ids%5B0%5D.keypart1=v1&ids%5B0%5D.keypart2=v2&ids%5B1%5D.keypart1=v3&ids%5B1%5D.keypart2=v4

If $params are in a batch complex key key, they are also prefixed by their key's position in the ids array, e.g. "ids[0].$params.parmkeypart1=v5"

When complex keys are used in batch requests, they are often included both in the URI and in the json body.

For example, a batch update request has the ids in the URI as well as the "entities" part of the body:


PUT /widgets?ids%5B0%5D.keypart1=v1&ids%5B0%5D.keypart2=v2&ids%5B1%5D.keypart1=v3&ids%5B1%5D.keypart2=v4

{
  "entities": {
    "keypart1=v1&keypart2=v2": {  }
    "keypart1=v3&keypart2=v4": {  }
  }
}

Note how the paths for the keys in the URI are prefixed by an ids array position, but the paths for the keys in the json body are not.

h3. Complex keys in batch requests in protocol 2.0

If used in batch requests, each key in the batch is represented as an element in the ids array using the protocol 2.0 array notation.

For example,


[
  { "keypart1":"v1", "keypart2":"v2" }, { "keypart1":"v3", "keypart2":"v4" }
]

It's serialized form is:


// Complex key as a serialized string:
ids=List((keypart1:v1,keypart2:v2),(keypart1:v3,keypart2:v4))

If $params are in a batch complex key key, they included in the same object as their id portion. e.g.


ids=List($params:(parmkeypart1:v5),keypart1:v1,keypart2:v2)

When complex keys are used in batch requests, they are often included both in the URI and in the JSON body.

For example, a batch update request has the ids in the URI as well as the "entities" part of the body:


PUT /widgets?ids=List((keypart1:v1,keypart2:v2),(keypart1:v3,keypart2:v4))

{
  "entities": {
    "(keypart1:v1,keypart2:v2)": {  }
    "(keypart1:v3,keypart2:v4)": {  }
  }
}

h3. Query parameters as complex types in protocol 1.0

Complex types work the same for query params as they do for keys. See the above sections for details. E.g. for a complex type:


{
  "a": 1,
  "b": 2
}

In protocol 1.0 a query param named "param1" of this type would be:


...?param1.a=1&param1.b=2

In protocol 2.0 a query param named "param1" of this type would be:


...?param1=(a:1,b:2)

h2. Empty list parameters

Suppose you have a finder called search with a parameter called filters which is a list of some type.

In protocol 1, if a client attempted to send an empty list the URL would look as follows -


/resource?q=search

Note that the parameter is lost in this case, and on the server side it would be treated as a null or uninitialized field. This was a bug in protocol 1!

We have fixed this in protocol 2. Here is how the URL looks in protocol 2 when you send in an empty list -


/resource?q=search&filters=List()

In other words, List() denotes an empty list in protocol 2. This applies to all cases in protocol 2 where lists are being used.

h2. Empty map parameters

Suppose you have a finder called search with a parameter called preferences which is a map of some type.

In protocol 1, if a client attempted to send an empty map the URL would look as follows -


/resource?q=search

Note that the parameter is lost in this case, and on the server side it would be treated as a null or uninitialized field. This was a bug in protocol 1!

We have fixed this in protocol 2. Here is how the URL looks in protocol 2 when you send in an empty map -


/resource?q=search&preferences=()

In other words, () denotes an empty map in protocol 2. This applies to all cases in protocol 2 where maps are being used.

h2. Empty string parameters

Empty strings are now a special case. They must be represented with two single quotes ''. Previously all empty Strings would simply appear as nothing.

|. Request Details |. Protocol 1.0 URL |_. Protocol 2.0 URL | | FINDER with string param; client attempts to send empty string | /resource?q=finderWithString&myStringParam= | /resource?q=finderWithString&myStringParam='' | | FINDER with list param; client attempts to send list containing a single empty string | /resource?q=finderWithList&myListParam[ 0 ]= | /resource?q=finderWithList&myListParam=List('') |

Clone this wiki locally