Note: I'm migrating from gonzalo123.com to here. When I finish I'll swap the DNS to here. The "official" blog will be always gonzalo123.com

      Handling AngularJs POST requests with a Silex Backend

      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

      comments powered by Disqus