As you may know, in order to pass user's informations(signed_request)
to your app, Facebook access canvas(ie: iframe) applications by
sending them a POST request. This mechanism is explained here.
In order to keep ReSTful, what would be the right place in Symfony (which service,
file...) to implement this Ruby on Rails' trick Pierre Olivier Martel
descibes here: http://blog.coderubik.com/2011/03/restful-facebook-canvas-app-with-ra...
, eg: convert every POST requests containing a 'signed_request'
parameter to a GET one?
You could implement a RequestListener like it is done in the RESTBundle: https://github.com/FriendsOfSymfony/RestBundle/blob/master/EventListener/RequestListener.php
Inspired from Stuck's answer(thanks!) and from Symfony Cookbook:
# src/Acme/FacebookBundle/RequestListener.php
namespace Acme\FacebookBundle;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
class RequestListener
{
public function onCoreRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
if ('POST' == $request->getMethod() && null !== $request->get('signed_request'))
{
$request->setMethod('GET');
}
}
}
Service Definition:
# app/config/config.yml
services:
acme.facebookbundle.listener.request:
class: Acme\FacebookBundle\RequestListener
tags:
- { name: kernel.listener, event: core.request, method: onCoreRequest }
Related
It's not clear to me how I should use the Symfony Form Component with FOSRestBundle for POST endpoints that I use to create resources.
Here is what I've got in my POST controller action:
//GuestController.php
public function cpostAction(Request $request)
{
$data = json_decode($request->getContent(), true);
$entity = new Guest();
$form = $this->createForm(GuestType::class, $entity);
$form->submit($data);
if ($form->isValid()) {
$dm = $this->getDoctrine()->getManager();
$dm->persist($entity);
$dm->flush();
return new Response('', Response::HTTP_CREATED);
}
return $form;
}
What I do is:
Send an application/json POST request to the endpoint (/guests);
Create a form instance that binds to an entity (Guest);
Due to the fact that I'm sending JSON, I need to json_decode the request body before submitting it to the form ($form->submit($data)).
The questions I have:
Do I really always have to json_decode() the Request content manually before submitting it to a Form? Can this process be somehow automated with FosRestBundle?
Is it possible to send application/x-www-form-urlencoded data to the controller action and have it handled with:
-
$form->handleRequest($request)
if ($form->isValid()) {
...
}
...
I couldn't get the above to work, the form instance was never submitted.
Is there any advantage of using the Form Component over using a ParamConverter together with the validator directly - here is the idea:
-
/**
* #ParamConverter("guest", converter="fos_rest.request_body")
*/
public function cpostAction(Guest $guest)
{
$violations = $this->getValidator()->validate($guest);
if ($violations->count()) {
return $this->view($violations, Codes::HTTP_BAD_REQUEST);
}
$this->persistAndFlush($guest);
return ....;
}
Thanks!
I'm trying to do the same thing to you and it's difficult to find some answers for this subject. I think today it's an important subject to develop website with api rest for mobile apps. Anyway!
Please find my answer below:
Do I really always have to json_decode() the Request content manually before submitting it to a Form?
No, i get data like this
$params = $request->query->all();
$user->setUsername($params['fos_user_registration_form']['username']);
Can this process be somehow automated with FosRestBundle?
I don't think so.
Is it possible to send application/x-www-form-urlencoded data to the controller action and have it handled with
Yes, but i'm currently trying to handle my form like that and I can not do it.
Is there any advantage of using the Form Component over using a ParamConverter together with the validator directly - here is the idea:
No
I'm guessing if I'm not going to only register the user with:
$userManager = $this->get('fos_user.user_manager');
and make my control manually.
I posted an issue here and i'm waiting:
https://github.com/FriendsOfSymfony/FOSUserBundle/issues/2405
did you manage to get further information ?
We got a Web API webservice with entity framework and accept JSON calls.
We have a call named: GetResidents which lists all residents. We would like to have an extra parameter (hash) which allows the caller to filter the results on the server.
Like this:
{"filter":{
"and":{
"age":{
"less_than":80,
"greater_than":60
}
},
{
"active":{
"eq":true
}
}
In RoR in the past I've used this gem which works great: https://github.com/QutBioacoustics/baw-server/wiki/Rails-API-Spec:-Filtering Does something similar exist in WebAPI?
Thanks for any feedback.
Use OData. Here is documentation link. Basic example:
public class ResidentsController : ApiController
{
[Queryable]
public IQueryable<Resident> GetResidents() {}
}
For your json:
http://localhost/api/residents?$filter=age lt 80 and age gt 60 and active eq true
im new to zend framework and would like to create a web portal which offers a services .
The services would be used by webapplication and mobile application both.
I'm using Chris Danielson's article
http://www.chrisdanielson.com/2009/09/02/creating-a-php-rest-api-using-the-zend-framework/) as the base for.
My question is am i going in the right direction .currently im accessing the services as
http://www.zendrestexample.com/version .
1) I require it to use the url as http://www.zendrestexample.com/api/version
instead.
2)Do i need to use zend restserver for writing services ?
3)can i use the same service for both mobile app and the web app ?I mean any redirects problem arise?
4)Do i need to usezend rest client to consume those service ?
Pleas help me out..
Well you are not using bunch of PHP files to get this done... so I think you are on the right track =). The implementation in the article is okay, but very old... was written > 4 years ago. I would suggest looking into Zend_Soap_Server, Zend_Json_Server or Zend_Rest_Server. Soap solution is a bit heavy for the mobile in my opinion.
Just decide on the implementation and do little planning!
I wrote a web application and later had to add services layer in order to add mobile app interface to the application. Unfortunately this was not part of initial requirements so had to redo many things.
My advice is as follows (if you webapp and api are in a same project):
code all your application logic in library or in controller helpers. So same code can be reused in the main web application and in API layer
code your webapp logic in default module
code your api layer in a dedicated module called 'api'
phpdoc must be perfect in order for zend to autogenerate the SMD
For the API use standard JSON-RPC 2.0 protocol, there are clients for both Android / iPhone that utilize this and provide auto-discovery (SMD like WSDL but for json). All request sent via GET result in SMD being displayed all others result in handling of the request.
Utilize Zend_Json_Server for your API layer.
Here is an functional example :
<?php
// API Controller Example
class ApiController extends Zend_Controller_Action
{
public function init()
{
parent::init();
$this->getHelper('ViewRenderer')->setNoRender();
}
public function helloWorldAction()
{
$this->_handleRequest('App_Api_HelloWorld');
}
protected function _handleRequest($handlerClassName)
{
//
$this->getHelper('ViewRenderer')->setNoRender();
//
$server = new Zend_Json_Server();
$server->setClass($handlerClassName);
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
$cfg = Zend_Registry::get('config');
$req = $this->getRequest();
$reqUrl = $cfg->paths->basehref . $req->getControllerName() . '/' . $req->getActionName();
$server->setTarget($reqUrl)
->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);
$smd = $server->getServiceMap();
header('Content-Type: application/json');
echo $smd;
} else {
// handle request
$server->handle();
}
}
}
// HANDLER Class Example
class App_Api_HelloWorld extends App_Api_ApiHandlerAbstract
{
/**
* says "hello world"
*
* #return string
*/
public function hello()
{
return 'hello world';
}
/**
* says "hello $name"
*
* #param string $name
* #return string
*/
public function hello2($name)
{
return "hello $name";
}
/**
*
* #return string
* #throws Exception
*/
public function hello3()
{
throw new Zend_Json_Server_Exception('not allowed');
return '';
}
}
Here is sample Request (I added some bootstrap magic to pickup session by id)
https://domain.com/api/hello-world
{
"session_id": "4ggskr4fhe3lagf76b5tgaiu57",
"method": "hello2",
"params": {
"name" : "Alex"
},
"id": 123
}
Review JSON RPC 2.0 Documentation.
I found Advanced REST Client for Google Chrome to be BEST extension for developing and testing JSON web services.
For additional security you can restrict ALL the request via HTTP Auth by adding few lines of code to the abstract controller or even create security controller plugin.
Good Luck.
I'd like to provide REST API in this way:
GET /api/devices
POST /api/devices
PUT /api/devices/1
DELETE /api/devices/1
This is my configuration:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
And these are the actions:
public IEnumerable<Device> Get()
{
//return all devices
}
public Devices Get(id)
{
//return a specific devices
}
and so on.
The issue appears when I want to handle nested resources:
GET /api/devices/1/readings
POST /api/devices/1/readings
GET /api/devices/1/readings/1
PUT /api/devices/1/readings/1
DELETE /api/devices/1/readings/1
This is my configration for these:
config.Routes.MapHttpRoute(
name: "NestedApi",
routeTemplate: "api/{controller}/{parentResourceId}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
The issue shows up when trying to GET and POST to the nested resource:
[HttpGet]
public String Readings(int parentResourceId)
{
//return a list of readings for the device
}
[HttpPost]
public String Readings(int parentResourceId)
{
//create and return the id of a reading for the device
}
This is, of course, failing because there are two actions with the same signature.
I'd like to hear from a way of accomplishing this with the most RESTful approach
Microsoft is adding Attribute Routing to increase the flexibility of the routing system.
Have a look at their documentation on Scenario 3
There is also some answers on Stack Overflow like:
How to handle hierarchical routes in ASP.NET Web API?
There are solutions based on specifying route mappings but if you want more a more generic solution, this is by far the best solution I have seen related to this topic. Of course, Web API 2 has attribute routing.
I have troubles to do REST application in CakePHP, requesting GET /admin/quote_authors/1.json sends me to the 'view' action, not 'admin_view'.
route.php:
Router::parseExtensions('json');
Router::mapResources(array(':controller'), array('prefix' => '/admin/'));
QuoteAuthorsController.php:
public $components = array('RequestHandler');
public function admin_view($id) {
var_dump('admin view');
}
public function view($id) {
var_dump('view');
}
Thanks.
Answering because I can't comment.
You seem to be missing the action part of the request /admin/quote_authors/view/1.json
So for other request it would be like /admin/:controller/:action/:params in general.
And, of course, like thaJeztah said, remove the slashes of the prefix (that's why it's giving you that error, it's considering the parameter "1" as the action it has to execute)