On Thu, 14 Aug 2014 15:35:14 GMT, Mickaël Bouchaud wrote:

Hi,

I'm trying to make a REST API using vibe.d.

GET /resource to give me an array of resource available : it works

GET /resource/:id to give me a resource with matching id. It doesn't work and seems to register route to :id/resource instead. Is it possible to change this behavior ? How can I change this behavior without using UDA on all my API method ? Is there a reason behind that behavior ? The resource/:id seems more natural to me.

DELETE /resource/:id I have the same problem and the delete method is mapped to /:id/resource

The API currently is built to map one interface to one resource like this:

interface API {
    private ResourceAPI m_resource;

    // mapped to /resource
    @property ResourceAPI resource() { return m_resource; }
}

interface ResourceAPI {
    // GET /resource
    auto get() { /* return list of resources */ }
    // GET /resource/:id
    auto get(int id) { /* return resource */ }
    // DELETE /resource/:id
    auto erase(int id) { /* delete resource */ }
}

However, this is often not ideal for nested resources (where each resource has an ID), so there will probably be another way to achieve this apart from using manual attributes at some point.

POST /resource with value

  	{
  		"firstName": "demo",
  		"lastName": "toto"
	}

failed.
I have an id in my struct and this seems to be mandatory. How is it possible to declare that fields of my struct are not mandatory.

POST /resource with value

  	{
  		"id": 33
  		"firstName": "demo",
  		"lastName": "toto"
	}

failed.
It seems that the default behavior is waiting for something like :

{
  "resource":
  	{
      "id": -33,
  		"firstName": "demo",
  		"lastName": "toto"
	}
}

Adding @optional or maybe @ignore should make this work. See vibe.data.serialization for the list of supported attributes.

Is there a way to change the behavior of vibe.d so the add method is mapped to something waiting for JSON value instead of a JSON object having a field matching the add method parameter ?

Currently the only way is to use the @before attribute like this:

@before!(extractJsonValue!float)("_value")
void add(float _value)
{
}

T extractValue(T)(HTTPServerRequest req, HTTPServerResponse res)
{
    return deserializeJson!T(req.json);
}

The underscore excludes the parameter from the usual JSON field mapping process, and the @before attribute causes it's value to be computed using a custom function instead of sourcing it from the req.params map.

To make this a bit prettier on a larger scale, you could also define an alias:

@jsonValue!float
void add(float _value)
{
}

template jsonValue(T) {
    T extractValue(HTTPServerRequest req, HTTPServerResponse res)
    {
        return deserializeJson!T(req.json);
    }
    alias jsonValue = before!extractValue("_value");
}

This also works for complex types, like the Customer struct.

I think such a feature would be valuable to have built into the system, it just needs a nice and backwards compatible syntax. The easiest approach would maybe be to just include the jsonValue attribute above in vibe.web.rest...

Disclaimer: I didn't run any of the snippets through a compiler, so there may be some mistakes.

Here is a gist with the source code i'm using.

Thanks for your help,