All,
So here's a question about a possible feature request we can add to Praxis, and I'd like to see what people think.
It is often the case that you need to manage/generate API URLs within the API code. I think that these fall usually into these two categories:
- generating hrefs. For example, to return as an HTTP redirect, or to embed "links" within a resource media_type or response.
- parsing received href parameters. For example, receiving hrefs within a create or update request, from which you need to parse their ids and perhaps resource types...
So, right now, Praxis allows some ways to do most of those things, but they are very low level. (And not well documented, actually). For example, if you have an action defined in your Blogs resource definition like this:
class Blogs
include Praxis::ResourceDefinition
media_type MediaTypes::Blog
action :show do
routing { get '/:id' }
params do
attribute :id
end
end
end
you can get a hold of the action path with:
resource_path = Blogs.actions[:show].primary_route.path
which then you can use to generate hrefs to it with:
resource_path.expand( id: 2) => /blogs/2
and you can parse parameters out of an incoming href to that action by:
resource_path.match("/blogs/12345")[:id] => "12345"
...but I think that we can do better, much better to make those processes simpler. So, to really build more help around that I propose that we introduce the concept of a "canonical resource URL". That will allow Praxis to know what URL to use to either create or parse one of a given resource type (i.e. a given ResourceDefinition). Once Praxis knows that, we can easily build wrappers to do what we want in a much cleaner way.
Here's an initial proposal:
- Add a "canonical_href" DSL to a ResourceDefinition class, so it can point to which of the currently defined action routes should be considered the main URL that uniquely identifies the resource type it represents. This will be typically the "show one member" action, however the application decides naming it.
- Add helper functions in the ResourceDefinition to generate and parse canonical hrefs to the resource (perhaps expose those from the controller too)
Here's how it could look like:
class Blogs
include Praxis::ResourceDefinition
media_type MediaTypes::Blog
canonical_href :show <<<<<<<<<<<<<<<<< NEW DSL
action :show do
routing { get '/:id' }
params do
attribute :id
end
end
end
And then, in the controller we could add helpers to the ResourceDefinitions to do things like:
Blogs.canonical_href(id: 123) => /blogs/123
Blogs.parse_href("/blogs/123") => {id: 123} #which I believe we can even coerce to the right type
Note that routes can perfectly have many more than a simple :id attribute.
We can also expose these helpers as instance or class methods in the controller (as opposed to class methods in the ResourceDefinitions) if we thought it was cleaner. That is easy since controllers have a pointer to their corresponding ResourceDefinitions.
I'm not really liking the names...but I think you get the gist.
Also note that if a given action has more than one route defined, we'd always use the 'primary' one. That seems to be a reasonable thing as it is easy to move the canonical route to the first one in the routing block, plus one can easily name the routes appropriately if need be)
Thoughts? Does this sound like something you'd like to use? do you have suggestions as to how this can be exposed better?...
Josep M.