I'm trying to figure out how codable routes with parameters in Kitura work. The default example is always something simple like:
GET /todos
GET /todos/<id>
What I'm looking for is:
GET /todos/<id>/details
Is this possible with codable routes? Or do I have to go back to the old routing version?
Unfortunately, this is not yet possible with Kitura's Codable routes - as you identified, only a trailing :id is supported.
Being able to move the single :id parameter elsewhere within the path might be possible in a relatively small patch. Supporting multiple path parameters would be significantly more complex: Codable routing would need to call your route handler with the right number of (individually typed) parameters. Perhaps there's a half-way house where we could support an array of path parameters (all of a single type).
If you'd like to raise an issue against Kitura and elaborate on your use cases, we could discuss possible solutions and whether they could reduce the need to fall back to 'traditional' routing.
Related
I have a large Catalyst app and want to get a list of all endpoints it supports (bonus points if it can tell me if the request method). Is there some easy way to ask Catalyst to list them?
Catalyst does not know the full set of paths. The true dispatch paths are resolved dynamically, iterating through DispatchType classes until one responds favourably to a call of match.
The debug option does a one-time enumeration of all possibilities that your controllers allow. If you want to interfere with this, you have to look at Catalyst::Dispatcher::_display_action_tables
It's a tree-walking algorithm that iterates through each route it finds at '/' and follows each subsequent route that $controller->actions returns. It's not easy to read, but you could conceivably implement a version of _display_action_tables that doesn't just print to a table, but does something else instead. Then call it in the live application with $c as argument and see what happens!
Let's say I want to make a RESTful interface, and I want to work with foos based upon their IDs. Nothing new here:
GET /api/foo1 returns a representation (e.g. using JSON) of foo1.
DELETE /api/foo1 deletes foo1.
etc.
Now let me tell you that a "foo" is a collection type thing. So I want to be able to add a "bar" to a "foo":
PUT /api/foo1/bar3 adds bar3 to foo1.
GET /api/foo1/bar3 returns a representation of foo1.
DELETE /api/foo1/bar3 removes bar3 from foo1.
DELETE /api/foo1 deletes foo1 altogether.
Now the question remains: what does GET /api/foo1 do? Does it it simply return a representation of foo1 as I originally assumed in this question? Or does it return a list of bars? Or does it return a representation of foo1 that is both a description of foo1 as well as includes a list of all contained bars?
Or should GET /api/foo1 merely return a representation of foo1 as I assumed at the beginning, and require a PROPFIND request to list the bars inside foo1 (the approach taken by WebDAV)? But then in order to be consistent, wouldn't I have to change all my other list-type functionality to PROPFIND, directly contradicting all those thousands of RESTful tutorials that say to use GET /api/foo1 to list the contents?
After some pondering, I think the best conceptual explanation from a RESTful perspective is that usually the "thing" is not the same thing as its "collection". So while in the WebDAV world a directory/ might be the same thing that holds its files, in the RESTful world I might have a separate directory/files/ subpath for the contained files. That way I can manipulate directories separately from the files that hold.
Consider a RESTful API for a farm which contains barns. The endpoint farm/api/barns/ might return a list of barns, one of which would be farm/api/barns/bigredbarn. Naively I would think that retrieving farm/api/barns/bigredbarn/ would provide me a list of animals in the barn, which is what prompted this question.
But really the animals in the barn is only one aspect of the Big Red Barn. It might contain vehicles and hay:
farm/api/barns/bigredbarn/animals/
farm/api/barns/bigredbarn/vehicles/
farm/api/barns/bigredbarn/haybales/
With this approach the dilemma I faced does not arise.
The semantics of webdav has never really been reconciled with the idioms of RESTful interfaces.
In theory, GET should retrieve a representation of a state of a resource and PROPFIND should be used to retrieve the members of a collection.
So you should do this:
GET /api/foo1/ - returns state of foo1 only
PROPFIND /api/foo1/ - returns the members of foo1
Most front end devs would freak out if you told them to use PROPFIND, although its completely supported in browser js implementations.
Personally i use a webdav/json gateway, where requests are made using RESTful idioms, but routed to my webdav implementation
For example i would do this:
GET /api/foo1/_PROPFIND?fields=name,fooProp1,fooProp2
And that would return
[
{ name : "bar1", fooProp1: "..", fooProp2 : ".."},
{ name : "bar2", fooProp1: "..", fooProp2 : ".."}
]
One advantage of this approach is that client's get to control the json properties returned. This is good because a rich API will have a lot of properties, but in most situations clients dont need all of them.
The routes and their operations in RESTfull API are completely designed by the developers. It's the developer who decides what to return while requesting a specific route say, GET /api/foo1.
And the developer should design every route including /api/foo1/bar. There is no specific rule on what a particular route should do. If your API is an open-source project make a clean and clear documentation of every route.
Don't waste your time thinking about the old school strategies.
I used the suggested approach in this question to return HATEOAS formatted outputs that match those returned by spring-data-rest. It works good, but is there a way to avoid boiler plate code to create entity resource assemblers like the QuestionResourceAssembler in the referenced question, if I only want to add 'self' links using the id to all entities? Perhaps using ResourceAssemblerSupport?
The easiest way is to simply use the Resource wrapper type:
Resource<Person> personResource = new Resource<>(person);
personResource.addLink(…);
personResource.addLink(…);
Links can be created either by simply instantiating them (i.e. new Link("http://localhost/foo", "relation") or by using the ControllerLinkBuilder which allows you to point to Controller methods for obtain a reverse mapping. See this section of the Readme for details.
I'm wondering where to put the edit, and new keywords by rest application. I'll use express-resource in a project, and the default settings are these:
GET /forums -> index
GET /forums/new -> new
POST /forums -> create
GET /forums/:forum -> show
GET /forums/:forum/edit -> edit
PUT /forums/:forum -> update
DELETE /forums/:forum -> destroy
There is a problem with this solution: there is not a real resource behind the new and edit. I mean the URL-s refer to resources, and after any slash is a sub-resource.
For example:http://my.example.com/users/1 represents:
var firstUser = {
name: "John Smith",
birthDate: new Date(1952,10,4),
hobbies: ["skiing", "football"],
...
}
And http://my.example.com/users/1/birthDate represents:
firstUser.birthDate
But by http://my.example.com/users/1/edit there is no such property:
firstUser.edit
So something is wrong with this conception.
Where is the real place of these keywords? In queryString or in headers?
From the perspective of a REST API these do not exist anywhere as they are not related to the representation of resources. They are actions upon resources and therefore expressed by the HTTP methods used. They would not bee needed if you were to create an external client that uses the API.
There is likely a need to provide some support for this type of functionality so that something like a UI could be presented, but that is the concern of the particular application and not the API itself. At that point it becomes discretionary but I would certainly avoid using headers as that would be pretty outside of conventional practice. But by headers it appears that you actually meant URI path. Out of those 2 I would say the path is the better option since it clearly defines any type of UI as a distinct resource and would keep it apart from the clean API, while using a query string on a part of the API would more tightly (mistakenly) associate it with the underlying resource.
Some update after a year or so:
edit and new should be hyperlinks
these links are just the representations of possible operation calls
by following them it is possible to manipulate the resource they belong by sending representations of the intended resource state, and/or by calling the proper methods
these terms are no resources, they don't have their own URL (resource identifier)
Thanks the advices Matt Whipple!
I think the best way to learn REST is reading the Fielding dissertation. There are many tutorials out there, but the authors of most of these does not really understand REST.
I want to have a REST resource for Foo and I want to be able to perform a POST to create a new Foo.
Foos can only be of two subtypes - Fizz and Buzz (the models are FooFizz and FooBuzz on the backend and both extend Foo). All Foos are either a Fizz or a Buzz. Most of the other models follow this pattern too (generic with subtypes for Fizz and Buzz). For the short and medium term, there will not be a new type added to Foos. In the long term it's more likely that this application will be obsolete before a new type is added, but the possibility exists.
At any rate, here are some URI schemes I came up with for working with Foos.
POST /foo?type=fizz
POST /foo/fizz
POST /fizz/foo
POST /foo-fizz
POST /foo/{foo-id}/fizz
My thoughts on this:
(1) might be unnecessary client-server coupling since it's dependent on the query string being properly formed. But it makes the most sense to me.
(2) and (3) are undesirable because you want to be able to have the URI go /foo/{foo-id} for performing operations on an individual Foo.
(4) requires Fizzes and Buzzes to become completely separate branches of the URI tree
(5) seems like a decent scheme although it might mess up the URI tree.
I'd be strongly tempted to just have a POST to /foo with the type of foo to be created (fizz or buzz) being determined by the contents of the document being POSTed. It would respond with a suitable redirect to the URI for the newly created foo (/foo/{fooId}, presumably) through which you'd manipulate things in the normal way.
Admittedly, I am not a REST expert, however here are my two cents.
Why would you even have a post to foo/{foo-id}? In that case, it would be more of a PUT for an update. The only time you would need to post would be if the id was being auto-created and unknown until actually created. So, in that case, I would lean towards 1 as you are creating a foo and the rest is just information needed to create foo. After that point, would you even need to care about the subtype (fizz or buzz)? I would assume the foo/{foo-id} would be enough information to work on it individually and determine the type from it.
So:
POST /foo?type=fizz
**You could possibly even remove the query string and send it in as your creation data, but that is up to you
GET /foo/{foo-id} ...retrieve the created foo
PUT /foo/{foo-id} ...update the created foo
DELETE /foo/{foo-id} ...delete the created foo
That is what I would do at least.
<soapbox>If you are really doing a RESTful architecture, then you shouldn't need to ask this question</soapbox>.
RESTful architectures include links in the representation that direct the flow of the application. If you are creating a new resource that is a child of a parent resource, then the representation of the parent resource should have an embedded link that tells you what URL and (potentially) which verb to use. Something like:
<link rel="add-child" method="POST" href="http://foo/1234">Add a new child</link>
If you are creating a wholly new root resource then, you probably want to POST to an absolute URL and have either the response document or Location header tell your application where to retrieve a new representation from. The target resource is essentially the "entry point" into your application's state machine.