RejectedSoftware Forums

Sign up

JSON as a parameter

Hi Folks,

Currently I am trying to get used to vibe.d REST framework, but have a
couple of questions.

I want to POST some JSON data through the API, but looks like I need to
specify all possible parameters with the function, for example:

import vibe.appmain;
import vibe.core.core;
import vibe.http.rest;
import vibe.http.router;
import vibe.http.server;
import vibe.data.json;

@rootPathFromName
interface API
{

@path("register") @method(HTTPMethod.POST)
Json postRegister(string a = null, int b = 0);

}

class MyAPI: API
{
override:

Json postRegister(string a, int b)
{
    Json j = Json.emptyObject;
    if (a !is null)
        j["a"] = a;

    return j;
}

}

shared static this()
{

auto settings = new HTTPServerSettings;
settings.port = 8080;

auto routes = new URLRouter;
registerRestInterface(routes, new MyAPI);

listenHTTP(settings, routes);

}

This looks OK, but suppose I have many fields associated with DB table
in backend, or I have sub-object in the JSON data, I would prefer to
process the POSTed data inside the function, not as function parameters.
So I wonder if I could get Json as a parameter.

The other thing is, with above example, if I want to set 'null' to field
"a", like {"a":null}, it doesn't accept it, like:

curl -k -H 'content-type: application/json' -X POST -d

'{"a":null,"b":1}' 'http://localhost:8080/api/register'
500 - Internal Server Error

Internal Server Error

Internal error information:
std.json.JSONException@/home/build/tmp/nativebuild/.build/src/gcc-4.9.0/libphobos/src/std/json.d(842):
Got JSON of type null
, expected string.

There are two issues here. First I cannot set 'null' explicitly in any
fields. Second, for integer value, apparently it does not allow 'null'
as default in function declaration, so if I don't put the field in
POST/PUT data, it will fall back to default integer value, while I
expect to leave the value if unspecified.

Thanks,

--Toshiaki

Re: JSON as a parameter

On Fri, 07 Nov 2014 15:50:12 -0800, Toshiaki Takada wrote:

[...]
This looks OK, but suppose I have many fields associated with DB table
in backend, or I have sub-object in the JSON data, I would prefer to
process the POSTed data inside the function, not as function parameters.
So I wonder if I could get Json as a parameter.

I could be wrong, but I don't remember any special handling for Json in the REST module.
So, I would recommend that you go for an aggregate (e.g. a struct) instead. This work as long as you have full control (e.g., you control both client and server).

The other thing is, with above example, if I want to set 'null' to field
"a", like {"a":null}, it doesn't accept it, like:

There are two issues here. First I cannot set 'null' explicitly in any
fields. Second, for integer value, apparently it does not allow 'null'
as default in function declaration, so if I don't put the field in
POST/PUT data, it will fall back to default integer value, while I
expect to leave the value if unspecified.

Thanks,

--Toshiaki

For the first issue (null string), you can either pass "" (empty string), and it will work (in D, assert("" is null) pass).
Also, if you use an aggregate, you can put the @optional attribute on it.
Finally, for the integer, Nullable!int are handled correctly (see std.typecons).

Re: JSON as a parameter

On 11/09/2014 12:13 PM, Mathias LANG wrote:

On Fri, 07 Nov 2014 15:50:12 -0800, Toshiaki Takada wrote:

[...]
This looks OK, but suppose I have many fields associated with DB table
in backend, or I have sub-object in the JSON data, I would prefer to
process the POSTed data inside the function, not as function parameters.
So I wonder if I could get Json as a parameter.

I could be wrong, but I don't remember any special handling for Json in the REST module.
So, I would recommend that you go for an aggregate (e.g. a struct) instead. This work as long as you have full control (e.g., you control both client and server).

The other thing is, with above example, if I want to set 'null' to field
"a", like {"a":null}, it doesn't accept it, like:

There are two issues here. First I cannot set 'null' explicitly in any
fields. Second, for integer value, apparently it does not allow 'null'
as default in function declaration, so if I don't put the field in
POST/PUT data, it will fall back to default integer value, while I
expect to leave the value if unspecified.

Thanks,

--Toshiaki

For the first issue (null string), you can either pass "" (empty string), and it will work (in D, assert("" is null) pass).
Also, if you use an aggregate, you can put the @optional attribute on it.
Finally, for the integer, Nullable!int are handled correctly (see std.typecons).

Thanks for the comment. Actually, I found I can use @before to pass
Json as a parameter, like:

Json getJson(HTTPServerRequest req, HTTPServerResponse res)
{

return req.json;

}

@rootPathFromName
interface API
{

@before!getJson("json")
Json postRegister(Json json);

}

--T

Re: JSON as a parameter

The way we are posting Json data to the server is by having a named parameter with the Json data. So your example:

Json postRegister(Json data) {
    import std.typecons;
    
    Nullable!int a;
    Nullable!int b;
            
    a.deserializeJson(data.a);
    b.deserializeJson(data.b);
    
    return data; // This will return a mirror of what was posted.
}

Then you should be able to post like this:

curl -k -H 'content-type: application/json' -X POST -d '{data: {"a":null,"b":1}}' 'http://localhost:8080/api/register'

And null should be accepted as valid JSON data (or it can be left out). It all depends on the way you want your API to work. Sorry I haven't had a chance to actually compile what I have written, but hopefully you can take something from it.