I was testing some custom resources using the built-in REST server and noticed that RESTServer::parseJSON() sets the optional second parameter for json_decode() to TRUE which specifies that objects in the JSON string should be forced into associative arrays. I was expecting (and would prefer) that objects in the JSON string be objects in PHP. While it's easy enough to cast an associative array to an object, it feels clunky because I'm then building logic into my resource method (as an aside, is "method" the right nomenclature to apply to the CRUD+I kind of requests on resources? "action" already has a different meaning in the context of the Services module) callbacks which could be deduced from the data being passed in. Perhaps more to the point is that I can imagine instances where someone *NEEDS* to change the behavior of either the JSON argument handler (e.g. tell json_decode to allow a nesting depth greater than 512 or something; yeah that's a little hard to believe but I'm sure my it gets my point across :).

Anyway, I suspect there's a deeper issue here which is whether or not it's logical to include the ability to pass additional parameters through to the argument-handlers that are in the REST server (and potentially other servers) or if those desiring that kind of control should simply be writing my own REST server implementation and/or passing the argument as a string and invoking json_decode() in the callback for that particular resource method. Or perhaps there's yet another alternative already in the codebase (or planned) that I'm unaware of and I just need to look around a bit more.

The most flexible approach for tackling this that I could come up with was adding another element to the associative array that defines the arguments to be passed to a resource's method. Something like "argument handler options" that is itself an array which gets sent along to the handler and overrides any defaults and/or is appended (e.g. for the specific use case of wanting JSON objects to come through at PHP objects, I'd want to pass something like 'argument handler options' => array('assoc' => FALSE) and have it override the default behavior of setting the second argument to TRUE json_decode()). I can see this opening its own can of worms, though.

I didn't write a patch since this isn't breaking anything and I'm not really certain of the "right" direction to take or if it should even exist in the Services module or the built-in REST server in the first place.

Comments

voxpelli’s picture

In #954964: Remove argument type 'struct' in favor of 'array' we decided that all resources should expect data to be associative arrays as that results in a simpler, more flexible interface.

It is possible for you to replace a format in the REST Server with your own parser - and to extend it with new formats and parser. However - since all parsers should parse data into arrays to support standard resources you wouldn't really be able to replace the JSON-parser the way you want.

I would say that this is a won't fix if you can't prove a case where associative arrays isn't enough. We've been down the path of supporting objects in Services 2.x and it caused a lot of problems in some areas.

(You might want to dig into the REST Server though - there's a lot of cool, often undocumented, extensibility in there)

t-dub’s picture

Status: Active » Closed (won't fix)

@voxpelli Thanks for the context and history! That's exactly what I needed as a Services newcomer. I went through the 3.x REST Server and found the spot where the json_decode() that's causing me angst is called and the "convert objects to arrays" option is hard-coded:json_decode(self::contentFromStream($handle), TRUE). It's really not a big deal at all and I think it would be *really* hard to demonstrate a need for objects over associative arrays.

I guess the larger issue about a standardized mechanism for passing options to parsers still stands, but I'm happy to table that until (if) I find a compelling use-case that truly requires that sort of capability.