JSON RPC 2.0: Do Extra Fields on Request Objects Violate Specification? - json

I am writing a JSON RPC conform js library. Are clients allowed by the specification to add custom fields (e.g. headers) along the params field to Request objects?
E.g.
{"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "headers": { "original-client": 12 }, "id": 1}
The spec (https://www.jsonrpc.org/specification#request_object) does not mention anything about adding additional fields.
Does my library violate the spec if it does add an header field?

Same question here. (I want to add user auth info / message signature...)
You are right in that the Specification does not mention anything about additional fields. So legally-speaking, if it is not forbidden, it is allowed.
On the other hand, I found at least one reference implementation here: www.simple-is-better.org/rpc/jsonrpc.py, which will hit you with an exception if a decoded message contains extra fields. This code is from one of the authors of the JSON-RPC 2.0 specs, Roland Köbler.
So, YMMV.
If your library is only an internal building block for a proprietary system, go ahead.
If you need to interface with other JSON-RPC implementations, test each one.
If the library is intended for public use, don't do it.
Edit: I solved this using the following protocol:
Before the "payload" message, send a standard-compliant notification with method "rpc.secinfo". (The rpc. prefix is per-spec reserved for extensions)
The "params" field contains whatever metadata applies (e.g. username, signature)
Example: {"jsonrpc": "2.0", "method": "rpc.secinfo", "params": {"user":"root", "signature":"0xDEADBEEF"}}<DELIM><payload><DELIM>
If header data is empty, No special method is pretended (i.e. behaves exactly like standard json-rpc).
The receiver can decode the header message just like any other call, and just needs to apply (check sig, whatever) the header onto the following message.
Discussion:
allows framing without touching payload
allows decoding the header without decoding payload
allows using byte-payload as is, particularly allows encrypted+literal payload to coexist (however encrypted payload breaks JSON-RPC compat!)
"Unaware" receiver: will throw the rpc.secinfo calls away silently or loudly, but is able to operate. Missing ID indicates a notification, i.e. receiver will not send response back per JSON-RPC spec.
"Unaware" sender: Received messages are valid, no-header messages.
Feel free to reuse this protocol, but please credit this SO answer.

Related

How to specify the content-type and the content-transfer-encoding of a specific field in my JSON API response?

I'm developing an API which, given a request-body with certain contents, generates a document that can be in different formats (e.g. pdf, png, etc). Given that the document can be a binary file, the file is base64-encoded and placed within a json response that looks like this:
{
"document": "document base64-encoded"
}
The response might contain other fields but they are not relevant to the question.
My question is:
What is the best way to specify the content-type (e.g. pdf) and the content-encoding (e.g base64) of the field document?
I thought of some options but I would like to hear your recommendation.
My options
Use header parameters Content-Type and Content-Transfer-Encoding: I assume this option would be wrong as these parameters apply to the message itself which in this case is application/json without any encoding.
Specify custom-parameters (e.g. x-document-content-type and x-document-content-tranfer-encoding.
Include such metadata within the response-body like this:
{
"document": {
"content": "document base64-econded",
"type": "pdf",
"econding": "base64"
}
}
Thanks for your input!
There are 2 layers of communication here, each with their own contract/protocol. Your own JSON API protocol, being sent over the HTTP protocol. You should stick to HTTP standards to comply with the contract of that layer, and it is up to you to define the contract of the JSON data.
The mentioned HTTP headers are used to tell the user-agent/client what the MIME-type of the accompanying HTTP body is. This must be application/JSON to comply with the HTTP standard. If you diver from this it will not be valid HTTP traffic anymore and a regular, well configured HTTP client wouldn't be able to consume your API.
The JSON body inside the HTTP message can be filled with whatever you find is necessary for a consumer of your API to use the encoded contents. You are defining your own contract here, so it is really up to your needs and that of the consumers of your api.
Do you use other content encodings as base64? If so, then you can specify the encoding of the data.
Do you provide multiple different file types? Then it's useful to add the content-type of the encoded data. Be aware that the header of the encoded content might already contain information about the type of the contents of the file.
P.s. it would probably be better to provide the "type" as you name it, as a mime-type. This is more common as a known standard for defining content types.

Inconsistence between REST POST and GET entity format?

I'm creating an API for submitting incoming email messages for internal processing. The mail server script will submit them in a simple format like, pretty much exactly as received:
POST /api/messages/
{
"sender": "sender#...",
"recipient": "recipient#...",
"email_message": "headers\nbody"
}
However upon submission the email_message is parsed, some fields are extracted, message body is parsed, etc, and what we actually store as the entity is this:
GET /api/messages/1/
{
"sender": "sender#...",
"recipient": "{our internal recipient ID}"
"subject": "Subject from email",
"date": "Date from email",
"parsed_body": "Output of some magic performed on the Email body",
... etc ...
}
As you can see this is quite different from what was submitted via POST in the first place.
Is this transformation permitted under the REST rules or should the entity be stored (and retrieved) as originally POSTed? And if it should be stored as is then what kind of API endpoint should I provide for submitting the unparsed messages?
Is this transformation permitted under the REST rules or should the entity be stored (and retrieved) as originally POSTed?
For POST, it's fine to store whatever makes sense. Think about how it works on the web; we fill out a form, which submits as a bunch of key value pairs, but the server makes no promise that it is going to store key value pairs.
PUT semantics are different; the client expects the new representation to overwrite the existing representation (if any), whatever that means. So you need to be more aware of the implications of those semantics, especially in regards to what assumptions the client is allowed to make as a consequence of various responses.
POST semantics are much more forgiving (and consequently, the client has less information available about what's going on; that's part of the tradeoff).

RESTful HTTP embedded hardware API - JSON field order significance

I'm working on a RESTful HTTP API for an embedded hardware device. In this API, hardware components are typically represented in a URI hierarchy of API Resources, which then have child JSON objects with attributes/fields specific to that hardware "object". To control/modify the hardware, a HTTP PUT request is sent with a content-body of JSON object containing desired fields to be changed.
My question is about the order of fields within a JSON request body. Let's say we are changing multiple fields in the same JSON object. Since a JSON object is, by definition, an "unordered collection of zero or more name/value pairs", this implies that the order of applying those hardware changes is also unordered/undefined, which might not be good.
For example, what if "setting1" must be configured before "state" is set? For example, the following might be sent as the content-body:
{
"setting1": 1234,
"state": "on",
}
But if we send the following instead, what happens? (Notice the "state" field occurs first.)
{
"state": "on",
"setting1": 1234,
}
The problem is, by default the context of the JSON Object is "unordered", so the behavior is uncertain.
If it could be established (perhaps through API documentation) that the order of JSON fields in a request is significant, would this be considered a violation of best-practices in the context of JSON and RESTful APIs? How have others dealt with this? I would be surprised if this has not been discussed already, but I have not been able to find anything.
I'm not certain, but I think that trying to impose an ordering restriction on clients is going to be problematic for some of them. I would bet that not all frameworks/JSON libraries will respect an ordering, at least not by default. If you control the client, this may not be a big deal, but it sounds like you don't.
Strictly speaking, you would have to send multiple PUT requests in order to ensure the updates happen in the correct order. That's the easiest to implement, but also the noisiest. Another option would be to instead support a PATCH call to the endpoint using the RFC 6902 format. That will let you control the order in which changes occur, but your clients need to build out PATCHes. You could also support a POST if neither of those appeal to you.

Why should JSON have a status property

I stumbled over a practice that I found to be quite widespread. I even found a web page that gave this a name, but I forgot the name and am not able to find that page on google anymore.
The practice is that every JSON response from a REST service should have the following structure:
{
"status": "ok",
"data": { ... }
}
or in an error case:
{
"status": "error",
"message": "Something went wrong"
}
My question: What is the point why such a "status" property should be required in the JSON? In my opinion that is what HTTP status codes were made for.
REST uses the HTTP means of communication between client and server, for example the "DELETE" verb should be used for deleting. In the same way, 404 should be used if a resource is not found, etc. So inline with that thinking, any error cases should be encoded properly in the HTTP status.
Are there specific reasons to return a HTTP 200 status code in an error case and have the error in the JSON instead? It just seems to make the javascript conditional branches more complex when processing the response.
I found some cases where status could be "redirect" to tell the application to redirect to a certain URL. But if the proper HTTP status code was used, the browser would perform the redirection "for free", maintaining the browsing history properly.
I picture mainly two possible answers from you:
Either there are two quarreling communities with their favorite approach each (use HTTP status always vs. use HTTP status never)
or I am missing an important point and you'll tell me that although the HTTP status should be used for some cases, there are specific cases where a HTTP status does not fit and the "status" JSON property comes into play.
You are right. I think what you are seeing is a side-effect of people not doing REST correctly. Or just not doing REST at all. Using REST is not a pre-requisite for a well-designed application; there is no rule that webapps have to be REST-ful.
On the other hand, for the error condition, sometimes apps want to return a 200 code but an error to represent a business logic failure. The HTTP error codes don't always match the semantics of application business errors.
You are mixing two different Layers here:
HTTP is for establishing (high-level) connections and transferring data. The HTTP status codes thus informs you if and how the connection was established or why it was not. On a successful connection the body of the HTTP request could then contain anything (e.g. XML, JSON, etc.), thus these status code have to define a general meaning. It does not inform you about the correctness or type (e.g. error message or data) of the response.
When using JSON for interchanging data you could certainly omit the status property, however it is easier for you to parse the JSON, if you know if it includes the object you were requesting or an error message by just reading one property.
So, yes, it is perfectly normal to return a 200 status code and have a "status": "error" property in your JSON.
HTTP status codes can be caused by a lot of things, including load balancers, proxies, caches, firewalls, etc. None of these are going to modify your JSON output, unless they completely break it, which can also be treated as an error.
Bottom line: it's more reliable to do it via JSON.

Mimetypes for a RESTful API

The Sun Cloud API at http://kenai.com/projects/suncloudapis/pages/Home is a good example to follow for a RESTful API. True to RESTful principles, when you GET a resource you get no more nor less than a representation of that resource.
The Content-Type header in the response tells you exactly what the type of that resource is, for example application/vnd.com.sun.cloud.Snapshot+json. Sun has registered these mimetypes with the IANA.
How practical is this in general currently? Most API's I have seen have used the Content-Type of "application/json". This tells you that the response is JSON but nothing more about it. You have to have something in the JSON object, like a "type" property, to know what it is.
I'm designing a RESTful API (which will not be made public, therefore I wouldn't be registering mimetypes). I have been using RESTEasy and I find that even if I specify a complete mimetype, the Content-Type in the response header will be exactly what the Accept request header specified. If the request asks for "application/*+json" by default the response header will have "application/*+json". I can probably fix this by changing the header before the response goes out, but should I try to do that? Or should the response have a wildcard just like the request did?
Or should I just serve up "application/json" like most APIs seem to do?
Additional thoughts added later:
Another way of stating the question is: Should I use HTTP as the protocol, or should I use HTTP only as a transport mechanism to wrap my own protocol?
To use HTTP as the protocol, the entity body of the response contains the representation of the object requested (or the representation of an error message object), the "Content-Type" header contains the exact type of the object, and the "Status" header contains a success or error code.
To use HTTP as merely a transport mechanism, the "Status" header is always set to 200 OK, the "Content-Type" is something generic like "application/json", and the entity body contains something that itself has an object, an object type, an error code and whatever else you want. If your own protocol is RESTful, then the whole scheme is RESTful. (HTTP is a RESTful protocol but not the only possible one.)
Your own protocol will be opaque to all the transport layers. If you use HTTP as the protocol, all the transport layers will understand it and may do things you don't want; for instance a browser will intercept a "401 Unauthorized" response and put up a login dialog, even if you want to handle it yourself.
I use my own vnd.mycompany.mymediatype+xml media types for many of my representations. On the client I dispatch to the appropriate controller class based on the media type of the returned representation. This really allows the server to control the behavior of my client application in response to the user following a link.
Personally, I believe that using application/xml and application/json are one of the worst choices you can make if you hoping to support REST clients. The only exception to this is when the client only uses downloaded code (like Javascript) to interpret the data.
Or should I just serve up "application/json" like most APIs seem to do?
I don't think so.
A media type is the only point of coupling between your RESTful web application and the clients that use it. The documentation of your media types is the documentation of your API. Your media types are the contract between your clients and your application. Eliminate the specific media type and you eliminate an important element that makes REST workable.
Sun has registered these mimetypes with the IANA.
Couldn't find any mention of that here. AFAIK, there is no requirement to actually register your custom media type with the IANA. The convention seems to be to use the inverted domain notation of application/vnd.com.example.app.foo+json, which prevents namespace conflicts. If and when your media type becomes stable and public, it might be a good idea, but there's no requirement. Could be wrong on this, though.
Will you get any value by specifying a complete mimetype? Would you do anything with the complete mimetype different than you would if the mimetype was application/json?
My 2 cents- If the API is not going to be made public, then I see no reason for a complete mimetype. A mimetype of application/json should be more than enough. You already know the type of json that the response is returning. If the API eventually becomes public, then worry about a complete mimetype... or just let people figure it out.