14.4. How do I send complex objects as parameters?

QUESTION: The REST client is sending complex objects as a list of standalone parameters: for example, firstName, lastName, birthDate, etc. The backend, which I'm developing, has to turn these into high-level-language objects, such as User. How do I convert these arguments into objects?
ANSWER: The most straightforward way to do this would be a constructor to the complex object class (here, User) which accepts a map of key/value pairs; these would be the fine-grained parameters passed by the client. For example, in Java, class User could have a constructor with a single argument, of type Map<String,String>.
Now, how do we convert the map into a new object? In languages with good reflection mechanisms, such as Java or C#, it might be tempting to use reflection here: go over the map keys, for each map key try to find a data member in the class, and set that data member to the value mapped to this key. For example, if the first key in the map is firstName, a call to getField on the Class object representing this would provide you with a field object that can be used to set the actual field. A simple loop for setting all fields, and you're done!
I strongly advise against this approach. It could present a security risk (for example, you end up setting a private field. Do you really want to re-implement the language's security mechanisms?). It also circumvents any setters that might be defined for these fields, and which are used to enforce any class invariants. It is also probably not very efficient, though this is less of a consideration.
Instead, write simple, possibly "boring" code: for each field you'd like to set, find if a matching key exists in the map (note that the map key and the field name don't have to be identical now; the field could be firstName while the REST parameter was first_name). If found, pass the matching value from the map to the field's setter method.
Avoid validity checks in this constructor. If your code insists that first-name should be at least two letters long, this should be verified in the setFirstName method (or property setter, in C#). The most validity-checks that should appear in this constructor is in converting string values to non-string ones, for example for setting integer fields.

5 comments:

Kulbir minhas said...

Wanted to say thanks for insightful and sufficiently detailed information. Loved it...

Regards
Kulbir

Jared Thirsk said...

"for example, you end up setting a private field"

In C#, how about using reflection to work on properties, and only ones with a public setter? That way you can use public/private to control access (knowing that public means it is exposed via REST), and you get any normal validation you want via the setter.

Tyler Tift said...

You can do something similar to Jared's comment in Java. For a specific API, if you control flow with Struts 2 actions, the set function is called by default for every parameter passed as navigable by OGNL. It's pretty slick.

mallu nair said...

Still relevant in 2014 when several enterprises are embarking on their Digital transformation!!! Thanks very much.

mallu nair said...

What about your thoughts on REST Gateways and REST wrappers for existing SOAP services. Rather than a one to one 'proxy' type of calls, this REST gateway has to be more intelligent with orchestration, Is there a common pattern that can be leveraged for this.