CAKEPHP3 REST API point to a different controller? - rest

I believe I am missing something here. I am trying to point a route to a custom controller:
Router::scope('/myAPI/', function ($routes) {
$routes->extensions(['json', 'xml']);
$routes->resources('some_value',
[
'controller'=>'SomeValue',
'only' => ['index', 'create', 'update', 'delete'],
'id'=>'[0-9]+'
]);
});
Therefore the URL I am wanting is ~mydomain~/myAPI/some_value.
I would want this to point to the SomeValueController instead of looking for some_valueController. However the controller definition is ignored in this case and instead cakephp3 looks for some_valueController instead which I would rather avoid to try and keep with cakephp's naming conventions (and make use of the cake bake console to create a lot of controllers for models for me) but I would like to specify this custom URL.
What have I missed here?
Thanks,

Nevermind, if you TitleCase the name it works:
$routes->resources( 'SomeValue',
[
'only' => ['index', 'create', 'update', 'delete'],
'id'=>'[0-9]+'
]);
This allows the URL of some_value and points to the correct controller.
Posted just in case it helps someone else.

Related

Lumen POST Routes not Working

Consider the following:
$router->group([
'prefix' => 'api/v1/group',
'middleware' => 'auth'
], function () use ($router) {
$router->get('/', [
'as' => 'group.list',
'uses' => 'Api\V1\GroupController#list'
]);
$router->post('/', [
'as' => 'group.create',
'uses' =>'Api\V1\GroupController#create'
]);
$router->get('/{groupUUID}', [
'as' => 'group.retrieve',
'uses' =>'Api\V1\GroupController#retrieve'
]);
$router->put('/{groupUUID}', [
'as' => 'group.update',
'uses' => 'Api\V1\GroupController#update'
]);
});
As you can see, a pretty typical route setup. However, I'm seeing some incredibly odd behaviour - in short, the POST route seems to be being interpreted by the app as a GET route. When I make a POST request to api/v1/group (via Postman) I don't see the result of Api\V1\GroupController#create, but the result of Api\V1\GroupController#list.
I wondered if perhaps this was something to do with both routes having the same endpoint (shouldn't matter, but maybe it's different in Lumen? I usually work in full-on Laravel). So I commented out the get route. That made me just see a 404.
I then wondered if perhaps this entire route group was somehow broken. So I made two catchall endpoints:
$router->get('/{any:.*}', function () use ($router) {
return 'I am a get route';
});
$router->post('/{any:.*}', function () use ($router) {
return 'I am a post route';
});
And placed them at the top of the routes file, and commented out all other routes. Regardless of the route I hit or the method used, I always saw the same thing: I am a get route.
What's going on? What could cause my app to understand all POST requests as GET requests?
PS: It's also worth noting that these routes were working, until recently, without any real associated changes. Could something have been updated in a Lumen package that caused this?
PPS: I also tried using Insomnia instead of Postman, just in case it was a problem with Postman. Same result.
$router->get('/api/item/{table}/{id}', "ItemController#itemHandler");
$router->post('/api/item/{table}', "ItemController#itemHandler");
$router->put('/api/item/{table}/{id}', "ItemController#itemHandler");
$router->delete('/api/item/{table}/{id}', "ItemController#itemHandler");
I had pretty much the same issue. In my case - since I use Laravel Valet as development environment - I was able to make a POST request again, after serving the API locally over HTTP by executing valet unsecure my-project. On my production server, I still can use HTTPS, but for my local development environment, this solved the issue. Hope this helps some future readers.
Try api/v1/group/ (with trailing slash).

Zend routing: removing null parameters from the URL

If I have a route which is defined like this:
/event/:id/:instance_id/view
It appears in the URL like this when both parameters are set.
example.com/event/1/15/view
However, instance_id is optional, and therefore may be null, with the URL looking like this (as created by the url helper):
example.com/event/1//view
I want it to look like this:
example.com/event/1/view
How do I remove the unnecessary forward slash?
The above question is for Zend 1 and the below solution is for Zend 2, so please dis-regard my answer.
Your route does not say 'instance_id' is optional. You can achieve this by doing this
'route' => '/event/:id[/:instance_id]/view',
It should fix the url problem. Also ideally, 'view' should be after 'event', if it is possible in your scenario.
'route' => '/event/view/:id[/:instance_id]',
Any fix text should ideally come up first in the route and anything optional last.

Use route prefix with RESTful routes in CakePHP

Working on building an API and would like to use RESTful routes.
I got it to work just fine like this:
http://www.mysite.com/events.json // returns json results with my events
http://www.mysite.com/events/123.json // returns json results with event of id '123'
BUT - I want to be able to do this using an 'api' prefix.
So, I added the api Routing prefix:
Configure::write('Routing.prefixes', array('admin', 'api'));
And changed my actions from 'view' and 'index' to 'api_view' and 'api_index'.
But now it doesn't work. (eg. I have to write the action name or it won't find the correct one based on HTTP.
The end goal would be to be able to do something like this:
GET http://www.mysite.com/api/1.0/events.json // loads events/api_index()
GET http://www.mysite.com/api/1.0/events/123.json // loads events/api_view($id)
DELETE http://www.mysite.com/api/1.0/events/123.json // loads events/api_delete($id)
...etc
I ended up having to just write the routes manually:
Router::parseExtensions('json', 'xml');
Router::connect('/api/:version/:controller/:id/*',
array('[method]'=>'GET', 'prefix'=>'api', 'action'=>'view'),
array('version'=>'[0-9]+\.[0-9]+', 'id'=>'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'));
Router::connect('/api/:version/:controller/*',
array('[method]'=>'GET', 'prefix'=>'api', 'action'=>'index'),
array('version'=>'[0-9]+\.[0-9]+'));
Router::connect('/api/*', array('controller'=>'events', 'action'=>'index', 'ext'=>'html'));
Notes:
The [method] is what forces the HTTP type (eg. RESTful)
The parseExtensions() makes it so you can have it display the data in different formats automatically by changing the extension in your URL.
The last Router:: line was just a catchall for anything /api/ that didn't match - it forwarded it to the homepage. Eventually I'll probably just route this to an API error page.
The 'ext'=>'html' of the last Router:: line was to keep parseExtensions from trying to use whatever extension was in the URL - if it's redirecting for reasons they made the call wrong, I just want it to go back to the homepage (or whatever) and use the normal view.
Try something like this.
Router::connect('/:api/:apiVersion/:controller/:action/*',
array(),
array(
'api' => 'api',
'apiVersion' => '1.0|1.1|'
)
);
With prefix routing
Router::connect('/:prefix/:apiVersion/:controller/:action/*',
array(),
array(
'prefix' => 'api',
'apiVersion' => '1.0|1.1|'
)
);
Will match only valid API versions like 1.0 and 1.1 here. If you want something else use a regex there.
I know this is an old post, but there is a routing method called mapResources which creates the special method based routing for you.
http://book.cakephp.org/2.0/en/development/rest.html
You put it in routes.php like so:
Router::mapResources(array('controller1', 'controller2'));
The docs have a nice little table showing how the requests are mapped to different actions, which you can always override if you need to.

Zend Routing / URL helper . Have a global parameter show up first in URL

Was curious if anyone knew the best way to implement the following: I have a parameter in my zend framework 1.12 app which effectively controls the 'scope' of things, and is a field in every table in my db to represent the scope of a row. It is a simple integer variable, and can be thought of as 'buildingID', so it controls which 'building' we are working with.
In a plugin, I have:
Zend_Controller_Front::getInstance()->getRouter()->setGlobalParam('building', DYNAMIC_INT);
which accomplishes what I need. When I build a URL with the URL view-helper I have my parameter, but it is always at the end of the parameter list. I know this is trivial from a programming perspective, but how would I achieve 'prepending' this global param to my url parameters?
site.com/admin/controller/action/param1/xyz/param2/xyz/building/2
to become
site.com/admin/controller/action/building/2/param1/xyz/param2/xyz ?
Open to any ideas. If you want me to overload the url view helper, can you provide some example code, because I had trouble setting up this class.
Thank you all!
You can use a custom route to accomplish this. Setup the route somewhere in your bootstrap file:
$route = new Zend_Controller_Router_Route(
':controller/:action/building/:building/*'
);
$router = Zend_Controller_Front::getInstance()->getRouter();
$router->addRoute('building', $route);
And then, assuming that the following has been called at some point prior to using the url view helper...
Zend_Controller_Front::getInstance()->getRouter()->setGlobalParam('building', DYNAMIC_INT);
...you can specify the route as the second argument of the helper:
echo $this->url(array(
'controller' => 'admin',
'action' => 'controller',
'param1' => 'xyz',
'param2' => 'xyz',
), 'building');
// /admin/controller/building/1/param1/xyz/param2/xyz

Using Zend Routes? to customized url

This is getting me confused.
How do I customize /state/state_name to be replaced by /state/state_name.php?
Initially state_name is a variable and I don't want each of the state to be an action in my StateController. Instead, I would like to take that variable and process it in a specific action loadAction() to deal with the contents.
This is because the url /state/state_name.php is already SEO optimized and I want it to stay in that form using Zend Framework.
Thanks for any help. Any suggestions would be gladly welcomed!
Maybe something like:
$route = new Zend_Controller_Router_Route_Regex(
'state/([^/]+)\.php',
array(
'controller' => 'state',
'action' => 'load',
),
array(
'state_name' => 1,
),
'state/%s.php'
);
But why is is so important to keep the .php suffix? If anything, it unnecessarily exposes the underlying server-side technology employed to construct the page. What if you later change the entire site to Ruby On Rails or to Django? Why tie yourself to PHP?
If you are really sweet for a suffix, then I'd imagine that .htm or .html is better. But even that leads you down a path with a potentially bad smell. What if you want to use this same controller to be the endpoint of an AJAX request that returns JSON or XML data?
Personally, I'd bail on the suffix.