I'm expecting to receive uri's like
/user/*/account/*
I've got a user function defined as
sub user :Path('/user') :PathPart('') :ActionClass('REST' ) {}
then
sub user_GET :PathPart('user') Chained('/') CaptureArgs(1) {
#do stuff
}
For accounts I'm defining them similarly.
sub account :Path('/account') :PathPart('') :ActionClass('REST') {}
sub account_GET :PathPart('account') Chained('user_GET') Args(1) {
#do stuff
}
So, the problem is when I set Chained in account_GET to 'user_GET' the server debug show that the path is set:
[debug] Loaded Chained actions:
.-----------------------------+--------------------------------------.
| Path Spec | Private |
+-----------------------------+--------------------------------------+
| /user/*/account/* | /mcp/user_GET (1) |
| | => /mcp/account_GET |
'-----------------------------+--------------------------------------'
When I set Chained in account_GET to 'user' the server debug shows:
[debug] Unattached Chained actions:
[debug] Unattached Chained actions:
.-------------------------------------+--------------------------------------.
| Private | Missing parent |
+-------------------------------------+--------------------------------------+
| /mcp/account_GET | /mcp/user |
'-------------------------------------+--------------------------------------'
The problem is that clearly that latter isn't being set up and the former is returning that it wasn't found.
So the problem is if I'm calling /user/12345/account/23456 how do I get that path set correctly when what appears to be the obvious path, Chained('user'), isn't being set and the less obvious path, Chained('user_GET'), simply isn't working?
Clients must follow the linking paradigm of the Web and treat URIs as opaque identifiers. REST API designers should create URIs that convey a REST API’s resource model to its potential client developers. In this post, I will try to introduce a set of design rules for REST API URIs.
Two different URIs map to two different resources. If the URIs differ, then so do the resources, and vice versa. Therefore, a REST API must generate and communicate clean URIs and should be intolerant of any client’s attempts to identify a resource imprecisely.
Instead, they should rely on the media type, as communicated through the Content-Type header, to determine how to process the body’s content. File extensions should not be used to indicate format preference. REST API clients should be encouraged to utilize HTTP’s provided format selection mechanism, the Accept request header.
URI: The Uniform Resource Identifier Explained. The concept of URLs is familiar to most people. A URL is a web address that is used to direct users to websites on the internet. But what is a URI? The concept of URIs was conceived of by the forefather of the World Wide Web, Tim Berners-Lee.
Personally, I'd go for something like the following in the user controller:
package MyApp::Controller::User;
...
# root of the chain
sub object: Chained PathPart('user') CaptureArgs(1) { ... }
The object
action above would load the user object into the stash. Now I'd have the user controller chained off the above like the following:
package MyApp::Controller::User::Account;
...
# chains to the action loading the user object and dispatches RESTy
sub account: Chained('/user/object') ActionClass('REST') Args(1) { ... }
# handle individual request methods
sub account_GET { ... }
sub account_POST { ... }
Here the account
action provides common data for the account_*
methods, which perform the actual operations.
Having method specific actions as parts of the chain (like having user
react to a POST request to the account
action) seems kind of counter-intuitive from a design standpoint. That might work, but I've never tried it.
The above examples are of course simplified. I usually have a base
action in every controller setting the namespace and a common parent action, and all other actions in the controller will chain off that one. Then I'll have an object
like above for loading single resources, and a root
for a root action of the controller. Since you can build any kind of tree structure, it is rather flexible. So the best solution is often depending on what your constraints are.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With