Handling AngularJS POST requests in Symfony
At Qandidate.com we started using AngularJS last year and I have to say it was love at first sight! Two-way databinding, testability, dependency injection, server communication...awesome!
Did I say server communication? We use Symfony 2 (which is awesome too) for our back end API’s. Unfortunately AngularJS and Symfony do not speak the same language out-of-the-box.
In this post I will show you how we automatically decode JSON requests so we can use it with Symfony's Request object using our symfony-json-request-transformer library (or class actually).
Proof of concept
AngularJS's $http service automatically sends a Content-Type: application/json
header when POSTing data, but Symfony is more of a
application/x-www-form-urlencoded
kind of guy.
Let's say your AngularJS app is posting a simple JSON object like:
{
"foo": "bar"
}
Now it's really easy to decode this in your Symfony controller:
public function postAction(Request $request)
{
$data = json_decode($request->getContent(), true);
echo $data['foo']; // bar
}
Simple, right? Too bad we can't use the ParameterBag interface in the Request object.
If foo
were optional and a sane default would be baz
you would normally do:
$foo = $request->request->get('foo', 'baz');
Fortunately we can replace a request (i.e. the ParameterBag) with our decoded JSON:
public function postAction(Request $request)
{
$data = json_decode($request->getContent(), true);
$request->request->replace($data);
echo $request->request->get('foo', 'baz'); // bar
}
Awesome! But that was only one controller action...
The right way
Copy and pasting this code to other controllers is very WET and we like DRY!
What if I told you you could apply this to every JSON request without having
to worry about it?
We wrote an event listener which - when tagged as a kernel.event_listener
- will:
- check if a request is a JSON request
- if so, decode the JSON
- populate the Request::$request object
- return a HTTP 400 Bad Request when something went wrong.
Check out the code at https://github.com/qandidate-labs/symfony-json-request-transformer!
Registering this event listener is really easy. Just add the following to your
services.xml
:
<service id="kernel.event_listener.json_request_transformer" class="Qandidate\Common\Symfony\HttpKernel\EventListener\JsonRequestTransformerListener">
<tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" priority="100" />
</service>
Exit through the gift shop
I have created a demo setup of AngularJS and Symfony apps to demonstrate the code I used in this post actually works. Check it out at https://github.com/qandidate-labs/symfony-json-request-transformer-example.
That's all folks!