How to access two similar but located in different API in a single Apigility project? - rest

Suppose we do have an Apigility URL like localhost:8888/user.
But I do have two API's in a single Apigility project, ApiOne and ApiTwo.
Doing a GET request from localhost:8888/user always returns resources generated by ApiTwo. But when I want to get the same user resource rom ApiOne because it is from a different DB I can't retrieve it. I already tried to supply the Accept media type with the proper version (hoping it would help), to access ApiOne (e.g. Accept application/vnd.apione.v1+json)

I'm guessing based on your question that you've got ApiOne with a route to /user and ApiTwo with a route to /user?
The problem is that they are not different routes. ZF2 is going to use (I believe) the one that is defined last in the combined configuration file. If you want to be able to use both API resources, you'll need to have different routes somehow. This could be literally changing one of them to something like /user1.
You could also theoretically route to two different endpoints for entities if you provide constraints on the id that would make them differentiable. What I mean is you could have both routes like this:
/api/user[/:user_id]
/api/user[/:user_name]
As far as the ZF2 router is concerned, at this point, those routes are identical. The variable parts user_id and user_name could be the same thing.
However, you'd need something else that makes the routes different. Apigility (and ZF2) allow for constraints on the parts of the URL. So you could put a constraint on user_id of [0-9]+ and a constraint on user_name of [a-z]+. These would make the routes mutually exclusive for entities, but the collection version of the routes is still the same.
Constraints are added in the route under options like so:
'router' => array(
'routes' => array(
'your-api.rest.user' => array(
'type' => 'Segment',
'options' => array(
'route' => '/user[/:user_id]',
'defaults' => array(
'controller' => 'YourApi\\V1\\Rest\\User\\Controller',
),
'constraints' => array(
**'user_id' => '[0-9]+'**,
),
),
),
'your-api.rest.username' => array(
'type' => 'Segment',
'options' => array(
'route' => '/user[/:user_name]',
'defaults' => array(
'controller' => 'YourApi\\V1\\Rest\\Username\\Controller',
),
'constraints' => array(
**'user_name' => '[a-z]+'**,
),
),
),
),
),
)
In this example, if no user_id or user_name were provided, the Username resource should be called since it is defined last.
Overall though, my recommendation would be that you change the routes so that they are different. The accept header with version is essentially used for versioning, not routing to a different API resource.

Related

How configure Zend\Di

I need a help with Zend\Di;
I'm tired on the task of write factories to my application using the Zend\ServiceManager, I want to understand how work the configuration in MVC environment of Zend\Di.
I see this post of #Ocramius, with some configuration in the module.config.php, in the top key di:
<?php
return array(
'di' => array(
'allowed_controllers' => array(
// this config is required, otherwise the MVC won't even attempt to ask Di for the controller!
'Application\Controller\GreetingController',
),
'instance' => array(
'preference' => array(
// these allow injecting correct EventManager and ServiceManager
// (taken from the main ServiceManager) into the controller,
// because Di doesn't know how to retrieve abstract types. These
// dependencies are inherited from Zend\Mvc\Controller\AbstractController
'Zend\EventManager\EventManagerInterface' => 'EventManager',
'Zend\ServiceManager\ServiceLocatorInterface' => 'ServiceManager',
),
),
),
// remaining config
);
Anyone can post a url to the doc of this configuration or more detailed examples here?
If you have a lot of different controllers and have a lot of services to choose from, then the ones with Configuration or Annotation should be the choices in this link: https://github.com/ralphschindler/Zend_DI-Examples
I think you should look at some libraries like Aura.Di or Pimple. They provide even powerful DI containers.
If you have minimal services to inject, use initializers. Check this out: http://akrabat.com/zend-framework-2/zendservicemanager-configuration-keys/

Is there a way to make a Zend Framework Application to act like Facebook in profile links?

My accurate question would be, is there any routes that can make possible that when i go
mydomain.com/profilename
it'd be redirect to the profile controllers instead of index, and sitll, if i provide no parameter, he'd load the index page, and even still, if theres a controller by that name, that he'd run that controller instead of searching for a profile...
Pretty much complicated i know, that's why i'm asking for your help, you geniouses! <3
Thanks in advance, Jorge.
ZF1 doesn't have route priority as such, but routes are matched LIFO (last in, first out). So as long as you were able to hard code controller names into your routes, and put this after your profile route, you could do something like this:
$router->addRoute('profile',
new Zend_Controller_Router_Route('/:profilename', array(
'module' => 'default',
'controller' => 'profile',
'action' => 'view'
))
);
$router->addRoute('something',
new Zend_Controller_Router_Route('/:controller/:action', array(
'module' => 'default',
'action' => 'index'
), array(
'controller' => '(foo|bar)' // names of your controllers
))
);
Alternatively, if this isn't possible, or you want a more robust (but more difficult) solution, I wrote a blog post a while back with a detailed explanation of how to achieve this with a custom route class: http://tfountain.co.uk/blog/2010/9/9/vanity-urls-zend-framework

Get nested ressources when using cakePhp restfull

I'm using cakePhp to create a Rest api (see http://book.cakephp.org/2.0/fr/development/rest.html) and I need to get nested resources. The documentation tells how to get let's say books implementing a URI /books.json. But does not tell how to get for example reviews for a given book. What I'm trying to make is somthing like this: /books/14/reviews.json that returns Review resources.
Can any one tell me hwo to make this?
See the Custom REST Routing section of the docs you've linked. In case the default routing doesn't work for you, you'll have to create your own custom routes that either replace or extend the default ones.
Your /books/14/reviews.json URL could for example be mapped to BooksController::reviews() likes this:
Router::connect(
'/books/:id/reviews',
array(
'[method]' => 'GET',
'controller' => 'books',
'action' => 'reviews'
),
array(
'id' => Router::ID . '|' . Router::UUID,
'pass' => array(
'id'
)
)
);
When placed before Router::mapResources() it should work fine together with the default routes.

How to assemble a URL back to the www route when inside a Zend_Controller_Router_Route_Hostname route?

I have spent hours trying to find a solution to this but doesn't appear to be much out there.
I currently have admin.domain.com point to the admin module which is easy to do like so:
$adminRoute = new Zend_Controller_Router_Route_Hostname(
'admin.domain.com', array(
'module' => 'admin'
)
);
$router
->addRoute('admin', $adminRoute->chain(
new Zend_Controller_Router_Route(
':controller/:action/*',
array(
'controller' => 'index',
'action' => 'index'
))
));
And all other routes will work as per the default routing so that www.domain.com/module/controller and www.domain.com/controller both work as expected.
However, if I am currently inside the admin module and want to assemble a URL which points back to the www.domain.com route, then how does one do this?
Unfortunately it's not a simple case of making the default route a Hostname route for www.domain.com because then you don't benefit from the 'optional' module param in the path. E.g.
$wwwRoute = new Zend_Controller_Router_Route_Hostname(
'www.domain.com', array(
'module' => 'default'
)
);
$router
->addRoute('default', $wwwRoute->chain(
new Zend_Controller_Router_Route(
':module/:controller/:action/*',
array(
'controller' => 'index',
'action' => 'index'
))
));
Will simply build all paths in the format www.domain.com/default/controller/action rather than www.domain.com/controller/action
The docs suggest that the default routing uses Zend_Controller_Router_Route_Module but i've tried that and it seems there's more to than just that.
Any ideas?
EDIT: I'm suspecting that you either need to do one way or the other i.e. have all modules on a subdomain and then route the requests strictly like so /controller/action/*, or, have modules as part of the route path. Otherwise, a module would be reachable via two URLs - module.domain.com and www.domain.com/module - obviously there are ways round this, and of course, you could just set up specific routes for each module thereby not relying on the 'optional' module feature of the default Zend routing.

Is it possible to do batch POST API calls?

I'm writing an app that makes a daily post as a user, and having benchmarked the PHP code that does this, it seems to take about two seconds per user. I'm dividing the work up in to chunks, and using multiple cron jobs to do each chunk. I'd like to scale to many thousands of users one day, but this kind of work load is just too much. It would take my server literally all day to post to each user one at a time using this method.
How do people normally do this? I've seen other apps that do it. Is there some way of sending all these posts off at once using just one API call? Using individual API calls per user is crazy slow.
Thanks.
On one hand, this is entirely dependent on the API.
However, you could use a multi-threaded or pseudo-parallel approach to this, such that your program sends, say, 100 HTTP POST requests at a time, rather than generating one request after another in series.
Since you're using PHP, multi-threading is out (I think) but this question is very similar to others. For example, see how these folks recommend curl_multi.
You can use batch query to achieve what you need.
The code for batch query is mentioned below. You can refer more about Facebook batch query at : http://25labs.com/tutorial-post-to-multiple-facebook-wall-or-timeline-in-one-go-using-graph-api-batch-request/
$body = array(
'message' => $_POST['message'],
'link' => $_POST['link'],
'picture' => $_POST['picture'],
'name' => $_POST['name'],
'caption' => $_POST['caption'],
'description' => $_POST['description'],
);
$batchPost[] = array(
'method' => 'POST',
'relative_url' => "/{ID1}/feed",
'body' => http_build_query($body) );
$batchPost[] = array(
'method' => 'POST',
'relative_url' => "/{ID2}/feed",
'body' => http_build_query($body) );
$batchPost[] = array(
'method' => 'POST',
'relative_url' => "/{ID3}/feed",
'body' => http_build_query($body) );
$multiPostResponse = $facebook->api('?batch='.urlencode(json_encode($batchPost)), 'POST');