This days I working a lot with AngularJs applications (who doesn’t?). Normally my backend is a Silex application. It’s pretty straightforward to build a REST api with Silex. But when we play with an AngularJs client we need to face with a a problem. POST requests “doesn’t” work. That’s not 100% true. They work, indeed, but they speak different languages.
Silex assumes our POST requests are encoded as application/x-www-form-urlencoded, but angular encodes POST requests as application/json. That’s not a problem. It isn’t mandatory to use one encoder or another.
For example
name: Gonzalo
surname: Ayuso
If we use application/x-www-form-urlencoded, it’s encoded to:
name=Gonzalo&surname=Ayuso
And if we use application/json, it’s encoded to:
{ "name" : "Gonzalo", "surname" : "Ayuso" }
It’s the same but it isn’t.
Imagine this Silex example.
use Silex\Application; use Symfony\Component\HttpFoundation\Request; $app = new Application(); $app->post("/post", function (Application $app, Request $request) { return $app->json([ 'status' => true, 'name' => $request->get('name') ]); });
This example works with application/x-www-form-urlencoded but it doesn’t work with application/json. We cannot use Symfony\Component\HttpFoundation\Request parameter’s bag as usual. We can get the raw request body with:
$request->getContent();
Our content in a application/json encoded Request is a JSON, so we can use json_decode to access to those parameters.
If we read the Silex documentation we can see how to handle those requests
http://silex.sensiolabs.org/doc/cookbook/json_request_body.html
In this post we’re going to enclose this code within a service provider. OK, that’s not really a service provider (it doesn’t provide any service). It just change the request (when we get application/json) without copy and paste the same code within each project.
use Silex\Application; use G\AngularPostRequestServiceProvider; use Symfony\Component\HttpFoundation\Request; $app = new Application(); $app->register(new AngularPostRequestServiceProvider()); $app->post("/post", function (Application $app, Request $request) { return $app->json([ 'status' => true, 'name' => $request->get('name') ]); });
The service provider is very simple
namespace G; use Silex\Application; use Symfony\Component\HttpFoundation\Request; use Pimple\ServiceProviderInterface; use Pimple\Container; class AngularPostRequestServiceProvider implements ServiceProviderInterface { public function register(Container $app) { $app->before(function (Request $request) { if ($this->isRequestTransformable($request)) { $transformedRequest = $this->transformContent($request->getContent()); $request->request->replace($transformedRequest); } }); } public function boot(Application $app) { } private function transformContent($content) { return json_decode($content, true); } private function isRequestTransformable(Request $request) { return 0 === strpos($request->headers->get('Content-Type'), 'application/json'); } }
You can see the whole code in my github account and also in packagist
Reblogged this on Dinesh Ram Kali..