Playframework RAML resource definition


#1

I am working on replacing the build in routes definition with a raml style alternative. While creating a first proof of concept I came across the problem of having no way to implement it and still be compliant with the spec.

Currently the routes definition in the play webframework looks like this:

GET    /users             controllers.UserController.list
GET    /users/:id         controllers.UserController.read(id)

I didn’t find a way to specifying the controller that handles the request in raml. Did I miss something?

An equivalent raml definition could look like that:

/users:
  get:
    controller: controllers.UserController.list

/users/{id}:
  get:
    controller: controllers.UserController.read(id)

Although this example is very scala/java specific there may be a way to generalize that.


#2

It feels like the better approach would be to keep the webframework controller assignments outside the RAML file and have them refer back to the RAML file – better because your interface (the API) is kept separate from its implementation. So the RAML file would be as it is today, but there would be a second file, specific to the Play framework, that would list the controllers and the resource paths and methods to which they’d apply. Not ideal because there’s a bit of repetition, basically between the resource+method in RAML and the resource+method in this other file.

But first, please explain: do you see starting out with a RAML file and scaffolding out (or otherwise generating) the Play framework implementation, or going the other way to generate the RAML file from the implementation, or something else?


#3

I don’t agree with your thought that referencing a controller in an API definition is a violation of the separation of concerns. But I guess thats a subjective opinion.

Even it violates the separation there are numerous reason why to still go that way, instead of defining another file that also contains the routes (as you said: repetition of method, path and parameters):

  1. Defining http routes in two different places will lead to inconsistencies
  2. Separating the documentation from the actual routing will lead to outdated documentations

I want to go with as little code generation as possible. So at first the only thing generated will be the routing between requests and controller code (that would be the same behaviour as it is right now in the framework, but simply replacing the custom routes file syntax with RAML). In future versions I want to use more of the defined properties, for example to ensure restrictions (like payload size, content-type, …).

One way to integrate controller definitions in RAML would be to allow custom attributes.


#4

I like the minimization of code generation, for sure. How about considering another approach: a convention-based one, with guidance supplied by RAML resourceTypes and perhaps traits. For example (from the Play docs), where your routing file has

GET   /clients/:id          controllers.Clients.show(id: Long)

your RAML file would have

/clients/{id}:
  type: member

and your framework would understand that for any resource that has a resourceType of member, the controller is always the name of the resource above this in the path (clients), with proper case-changes, and a GET method on it always maps to a method called show taking the uriParameter as its argument. We can keep going into more detail, but I first wanted to quickly share the direction with you.


#5

Thats actually a good idea. I thought about that too and it seems to work pretty well for the standard CRUD definitions. One could simply introduce a convention how the handling controllers need to be named.

There is only one point I am concerned about, what about actions on resources. Sometimes there is a need to define specific actions (e.g. lets say there is a hooks api at /hooks/{hookId} and one ones to trigger the hook through the API. A common way to do it would be /hooks/{hookId}/trigger).
Some might suggest to use

/hooks/{hookId}/actions/trigger

but I am not sure if that is the standard way to do it.


#6

I’m not sure there are conventional ways to do such things, mostly because the variations are endless. But usually I’ve found that, within a particular domain, natural ways emerge when you think about it a bit. For example, logging in seems a non-obvious REST action, but if you think of it as creating a session context, then a POST to /sessions makes a ton of sense.

So in your case, is there something specific you’d like to trigger this way? Even if not, think of the state you’re modifying: are you creating a new thing, or are you updating state? You might POST to /hooks/{hookId}/triggers where a trigger is thought of as an event that happened at some point in time. Or you might PATCH /hooks/{hookId} to set its status to triggered.

If this works, you could use the conventional approach above. If it doesn’t seem natural, then you could still have a file of overrides/extensions that your code looks at when it receives a method/resource pair for which you don’t have a conventionally-named controller, and in that file you tell it explicitly which controller to use.


#7

This project seems to do what you are looking for…