Skip to content

Rest.li 2.0 Proposed Changes

gmcmillan100 edited this page Dec 11, 2014 · 8 revisions

Overview

This is a summary of the wire protocol and developer API changes that the Rest.li team will be introducing in Rest.li 2.0. This is not an official list of changes! The purpose of this page is to document the changes we are planning to make for Rest.li 2.0 and is subject to change. When we release Rest.li 2.0 we will update the Rest.li protocol documentation to document the new protocol in detail, and we will also release a Rest.li 2.0 CHANGELOG with a list of all our changes.

The "2.0" (short for 2.0.*) is intended as a semantic version number to indicate the version contains backward incompatible changes,  "2.0" is not a rewrite of Rest.li, nor does it indicate a large set of new features for developers.

Deprecation Strategy:   All code marked deprecated in Rest.li 1.* is slated for removal.  We guarantee developers that if they upgrade to the most recent 1.* version of Rest.li and resolve all deprecated warnings,  that their code will compile against Rest.li 2.0 with they migrate to it.

What Does This Mean for the Rest.li Project?

  • Remove code that has been marked as deprecated for a long time
  • We can simplify key sections of the code base, resulting in less code to maintain and fewer touch points when making changes
  • A code base that is easier to build additional features and layers on

What Does this Mean for Rest.li Users?

  • Significant performance improvements for specific use cases, particularly those that make heavy use of query parameters
  • Simpler and more consistent developer API

Summary of Changes that Will affect Rest.li Users

  1. New URI representations (details below)
  2. Rename X-LinkedIn headers to X-RestLi. Specifically, X-LinkedIn-Error-Response will be renamed to X-RestLi-Error-Response, and X-LinkedIn-Id to X-RestLi-Id.
  3. Removing the existing batchGet implementation and making batchGetKV the new implementation of batchGet.
  4. Fix inconsistencies in the Java client builder code for setting parameters for Actions and Finders. If you have a param foo for your Action that generated client builder uses paramFoo to set its value. However, if you have a param foo for your Finder the generated client builder uses fooParam to set its value. We will fix this inconsistency and have both the client builders use <param name>Param (e.g. fooParam) to set the values
  5. Removing inconsistencies between getContext() and injection of params in resource implementations (details below)
  6. Remove the RPC related methods from our R2 interfaces

Note: If you are using the generated Java client builders and Java clients, you will not be affected by changes (1) and (2) above as our code internally handles differences between the 1.0 and 2.0 protocols. These changes only come into play if you are not using Java client builders and are handcrafting request URIs and manually parsing responses.

New URI Representations

Why are We Making These Changes?

URIs in Rest.li 1.0 are currently quite complex and hard to read. There are also several inconsistencies in our URI format. We believe that Rest.li 2.0 would be a good time to reduce this complexity, fix our inconsistencies, and improve our URI format.

How the URIs Will Change

(spaces added artificially to improve readability. Actual wire protocol will not use spaces)

Request Details Rest.li 1.0 URI Rest.li 2.0 URI
GET on a resource with primitive-type keys /resource/1 /resource/1
BATCH GET on a resource with primitive-type keys

/resource?ids=1&ids=2&ids=3&ids=4

/resource?ids=List(1,2,3,4)

GET on a resource with complex keys /resource/$params.a=value&$params.b=value&keyPart1=value1&keyPart2=value2

/resource/($params:(a:value,b:value), keyPart1:value1,keyPart2:value2 )

BATCH GET on a resource with complex keys

/resource? ids[0].$params.a=value&ids[0].$params.b=value&ids[0].keyPart1=value1&ids[0].keyPart2=value2& ids[1].$params.a=anotherValue&ids[1]$params.b=anotherValue& ids[1].keyPart1=value21&ids[1].keyPart2=value22

/resource?ids=List(($params:(a:value,b:value),keyPart1:value1,keyPart2=value2 ),($params:(a:anotherValue, b:yetAnotherValue),keyPart1:value21,keypart2:value22))

GET on an association resource (compound key) /resource/stringKey=string&longKey=5 /resource/(stringKey:string,longKey:5)
BATCH GET on an association resource (compound key) /resource?ids=stringKey%3Done%26longKey%3D1&ids=stringKey%3Dtwo%26longKey%3D2 /resource?ids=List((stringKey:one,longKey:1),(stringKey:two,longKey:2))
FINDER with a complex query parameter

/resource?q=myFinder&param.aList[0]=foo&param.aList[1]=bar&param.aList[2]=baz& param.anObject.aField=1&param.anObject.anotherField=value

/resource?q=myFinder&param=(aList:List(foo,bar,baz), anObject:(aField:1,anotherField:value))

Unlike Rest.li 1.0 URIs, Rest.li 2.0 URIs can also send empty maps/objects and empty list information in the URI.  If you attempted to send this sort of information previously, it would become lost, and treated as if it was a null/uninitialized field. Users had to work around this bug as fixing it would be a backwards incompatible change that we did not want to introduce in our 1.x releases. However, since 2.x will be backwards incompatible with 1.x we are free to make the following changes:

Request Details Rest.li 1.0 URI Rest.li 2.0 URI
FINDER with list param; client attempts to send empty list

/resource?q=finderWithList

(note the lack of myListParam at all)

/resource?q=finderWithList&myListParam=List()
FINDER with map param; one of the param's map values is an empty object

/resource?q=finderWithMap&myMapParam.key1.a=1&myMapParam.key1.b=2

(note the complete lack of key2 in the URI at all)

/resource?q=finderWithObject&myMapParam=(key1:(a:1,b:2),key2:())

Empty strings are now a special case. They must be represented with two single quotes. Previously all empty Strings would simply appear as nothing. Here is what the empty string looks like in a URI:

Request Details Rest.li 1.0 Rest.li 2.0
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('')

In general the above changes are changes to the way keys are encoded.  Since keys show up in other places the impact of this change is not constrainted to URIs.  In particular, response bodies that contain keys (like a response from a batchGetKV request, or a batchUpdate, etc.) will have the new encoding format.  Here are some examples of how keys will look in request or response bodies:

Key Type Rest.li 1.0 Rest.li 2.0
primitive key, long 3 3
primitive key, string someKey someKey
Compound Key, like those from an Association stringKey=string&longKey=5 (stringKey:string,longKey:5)
Complex Key* $param.a=value&$param.b=value&keyPart1=value1&keyPart2=value2 ($param:(a:value,b:value),keyPart1:value1,keyPart2=value2 )

*note that Complex Keys in response bodies do not contain their params, and in Rest.li 1.0, they are URI encoded.

Removing Inconsistencies Between getContext() and Injection of Params in Resource Implementations

If you want to access a query parameter in a method in your resource implementation you use the @QueryParam annotation. However, if you want to access a header value you have to do getContext().getRequestHeaders(...). If you are using a free form resource (i.e. one that implements the KeyValueResource interface) there is no way to access the context.

In order to remove the above inconsistencies we will use injection for query params as well as headers. The following table describes the changes:

Rest.li 1.0
Rest.li 2.0
Notes
getContext() @Context (on param)

To access ResourceContext, replace getContext() with a @Context injector.  E.g.

public Greeting get(Key key, @Context context) { ... }
@QueryParam @QueryParam  
@Projection @ProjectionParam Uniformly use the "param" suffix.
@ParSeqContext @ParSeqContext  
@Keys @KeysParam Uniformly use the "param" suffix.
@Context @PagingParam

Rename the pre-existing @Context to @PagingParam

@CallbackParam @CallbackParam  
@ActionParam @ActionParam  
  @HeaderParam

Add @HeaderParam("<header-name>") to read a particular request header.


Clone this wiki locally