Suggested changes

8 views
Skip to first unread message

Jay Paroline

unread,
Sep 27, 2009, 10:07:09 PM9/27/09
to JSON-RPC
At Grooveshark we use our own custom rolled RPC which incorporates
JSON. We decided not to use JSON-RPC because of a few key differences
from how we wanted to operate.

-Lack of support for headers in JSON-RPC

One of the big reasons why we didn't go with JSON-RPC is the lack of
support for headers in the request and response messages. Headers are
useful for conveying state information not necessarily related to the
method being called. For example, passing a communication token, or
sending notifications and alerts to the client.
A typical header looks something like this for us:
"header":
{"client":"xxx","session":"xxx","uuid":"xxx","clientRevision":"xxx","token":"xxx"}
If this were part of the JSON-RPC standard, the JSON-RPC version would
probably also belong as part of the headers.

-Lack of support for multiple errors

It's possible for a call to fail for multiple reasons, and it would be
ideal to be able to convey all reasons for failure at once. For
instance, imagine a call to register a user. That call can fail
because the username is already taken, the email address is invalid,
or they forgot to type in their password. But what if more than one of
those is true at the same time? It would be best for usability to be
able to identify *all* errors at the same time.

-Lack of support for different error levels

Many errors are critical, but support for non-critical errors and
warnings would be nice.

-Can't return error and result simultaneously.

As with the above point, sometimes it is possible for an error
condition to occur that doesn't prevent returning a result. Returning
to the user registration example, let's say we want to raise a warning
whenever a user chooses a password that is too weak? The user can
choose to ignore that warning and use the password anyway, so the call
should succeed but raise a warning.

-id is unnecessary

For our uses, the id serves no purpose whatsoever, so we omit it. In
my proposal, the id would be an optional part of the headers.

--

When we started our project, I didn't bother bringing up these issues
because it was just an internal project never meant for public
consumption. But I've since written some very efficient RPC server
code and have been thinking about releasing it to the community, but I
realize it would be detrimental to have multiple JSON-RPC-like
protocols out there.

Matt (MPCM)

unread,
Sep 28, 2009, 6:27:03 AM9/28/09
to JSON-RPC
Thank you for your post, it was interesting to read an alternative rpc
approach using json.

The primary data structure difference seems to be the headers property
in the object, which is a nice way to group additional details. Of
course users are welcome to and often do extend json-rpc by including
additional properties into the request object.

However I think we use the error concept in very different ways. To
achieve what you suggest in json-rpc that data would be returned as
part of a data structure in the result. The error object is basically
reserved for when the request was not processed due to a server error,
not a conceptual `failure` in the particular method. So all the things
you suggest are possible, only you would return object holding your
own result/error meanings as the result in the response object.

You mention that "id" is unnecessary for your purposes, is this
because you only make one call at a time and/or don't queue calls?
Though you do suggest there is a uuid, so if that is unique per call
this is basically serves the same purposes.

--
Matt (MPCM)

Jay Paroline

unread,
Sep 28, 2009, 7:29:27 AM9/28/09
to JSON-RPC
Hi Matt,

I'm glad to see that extending json-rpc by adding additional
properties on the request object like we are doing with headers is
allowed, that makes me feel better. :)

I see your point with the error stuff, all the non-fatal errors
*could* be made part of the result set, however that feels awkward to
me for one because in that case the client needs to check two
different places for errors, but for another it also makes the server
code less elegant, at least in my case. The RPC server "translates" a
call from the client into a call in our framework. Whenever possible,
every method in our framework has a primitive return type and for
consistency, data is *always* returned in that type. Errors and
warnings are placed on a stack, so things that don't care about errors
or warnings can ignore them and things that do care can check the
stack. In RPC server land, that means that the result object is
literally the result of calling whatever method corresponds to the
client's requests, and the "post processor" checks for errors and adds
them to the errors property in the returned object. To do it in a way
that is compatible with JSON-RPC but still works with our framework,
the post-processor would have to manipulate the result object
directly, which feels a bit wrong and seems like it could get pretty
messy.

I see now why you the "id" is part of the spec -- I hadn't considered
that, because as you guessed we don't ever batch calls. The UUID that
we pass actually isn't the same thing, it's a UUID generated by the
client, and it remains constant throughout a session. Adding support
for that would definitely require some reworking of my RPC code, but
it could be done. So I guess the main issue I have at this point is
just with errors. :)

Jay

Alexandre Morgaut

unread,
Sep 28, 2009, 8:35:15 AM9/28/09
to JSON-RPC

[Matt should like this]
One thing to consider is that once JSON-RPC becomes a standard
reference, all implementations should supports all its specified
features to say it supports JSON-RPC 2.0
To be widely implemented and become a standard not only on "paper" via
RFC or ISO or anything else, but also in facts in products, the battle
is easier if JSON-RPC is modularized
JSON imposed itself because it was simple, so people liked XML-RPC

-Lack of support for headers in JSON-RPC
As I can read it, the JSON-RPC 2.0 specification defines a list of
properties which must or must not be included into request and
response objects
It doesn't prevent from adding implementation specific properties
which should be considered as extensions
Has we talk in some discussions, additional properties might be
interesting to add shared contexts, or batch constraints.


-Lack of support for multiple errors
The first level of error handling is to be aware of problems and kind
of problems (error exists, here the code of its family)
This help default behavior when a problem occur and the client should
be upset by details in production mode, they'll be required only in
development and debugging mode
As the error is a JSON object, it is really easy to add it a stack
property for details in these mode. That kind of good extension.
ex:
{
"jsonrpc": "2.0",
"error": {
"code": -32603,
"message": "Internal error",
"stack":[
{"code": 4242, "message": "Memory full on line 42"},
{"code": 4201, "message": "Can't create resultset"}
]
},
id: "5"
}


-Can't return error and result simultaneously.
This is right as you say for warning or notice, but it shouldn't for
errors
Why not using a "warning" header (has HTTP does ;-) ). You might
define it as a string, an object with code and message, or directly a
stack.
"notice" and "log" headers could also be supported
That's another interesting extension
ex:
{
"jsonrpc": "2.0",
"result": -19,
"warning":"Some non locked values may not have been up to date
while computing",
"id": 2
}

-id is unnecessary
Actually you can set the same value to id in each request if you don't
need it
The recommendation is just not setting it to null, but it can be 0 or
false or any other scalar value.


So if you can think it as modules more server will be able to make
their choice and more important, choose from their priorities when
they try to implement most of these features


my 0,02 €
(I'm in France ;-) )


Alexandre

Jay Paroline

unread,
Sep 28, 2009, 10:03:31 AM9/28/09
to JSON-RPC
No fair. Your 0,02 € is worth more than my $0.02! ;)

I like this approach to multiple errors. Feels much cleaner than
Matt's suggestion of adding it to the result set. I'm not completely
in love with the idea of separating out errors and warnings rather
than allowing errors to have a severity and coexist with results, as I
would think that if clients choose to handle warnings they would do so
in the same place where they handle errors. Going with your proposal
the only change I'd really need to make me happy at this point is
removing this from the spec: "Exactly one of result or error MUST be
specified. It's not allowed to specify both or none," or replacing it
with "SHOULD" or "RECOMMENDED." :)

Jay

Matt (MPCM)

unread,
Sep 28, 2009, 12:18:40 PM9/28/09
to JSON-RPC
I'll take the metal rounds over the printed value any day, $ or € ;)

I appreciate what you are saying Jay. If you control the server and
the client you are welcome to extend it however you want, most of do.
If it works out please document it and let the rest of us know. : )

But I still believe the meta data you are talking about should
primarily reside inside the result. This is because the error object
primarily represents the failure to process. Stuff like line errors
and implementation specific error related details could be augmented
into there... (I do this with detailed PHP server errors), but items
like warnings or contextual 'errors' really do not belong there.

It would not be reasonable to expect client libraries to understand
your custom error details and translate that up to application above
it.

That gives the client two places to interpret meaning from the call.
We must do this with the result, but hard processing errors do not
require it. Sounds like your client specific functionally is mixed
with the response shape on both the error and result side, but I think
that is also a result of your framework setup, based on what you
posted

It is just a question of where you stick your meta data... I always
try to view json-rpc clients as a set of functions that make the calls
and interpret results minimally, only to pass them up to the next
layer of the application. Errors speak to state of the call being
made, results speak to what you asked... a weak password or an
unavailable username is a reflection of what you asked (and passed),
not of the fact that you asked.

In essence you `overloaded` the function's purpose, requiring a single
return, documented meta details from the invocation, then augmented
the meta data into the response's error context. I'd keep all of that,
but would say it all belongs within the result in entirety and should
be documented in your own method api as such. It is really the object
definition of what you might return in from complex method... my
production web applications work like this currently, and rarely do we
pass anything either way but complex objects.

This way the error property keeps it's meaning independent from the
server API and API's definition of `error`.

--
Matt (MPCM)
Reply all
Reply to author
Forward
0 new messages