Outro dia estava trabalhando bastante com aplicações AngularJS (quem nunca?). Normalmente o meu backend é uma aplicação Silex. É algo bastante direto construir uma API REST com Silex. Mas, quando usamos um cliente AngularJS, precisamos encarar um problema. Requisições POST “não” funcionam. Isso não é 100% verdade. Elas funcionam, na verdade, mas falam linguagens diferentes.
Silex entende que as requisições POST são codificadas como uma aplicação/x-www-form-urlencoded, mas o Angular codifica requisições POST como uma aplicação/json. Isso não é um problema. E isso não é obrigatório usar codificador ou outro.
Por exemplo:
name: Gonzalo
sobrenome: Ayuso
Se você está usando uma aplicação/x-www-form-urlencoded, será codificado assim:
name=Gonzalo&surname=Ayuso
E se você usa uma aplicação/json, é codificado assim:
{ “name” : “Gonzalo”, “surname” : “Ayuso” }
É a mesma coisa, mas são coisas diferentes.
Imagine o exemplo com Silex.
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') ]); });
Esse exemplo funciona com a aplicação/x-www-form-urlencoded, mas não com a aplicação/json. Não é possível usar o pacote de parâmetros Symfony\Component\HttpFoundation\Request como sempre. Podemos pegar requisições do corpo do elemento raw com:
$request->getContent();
O conteúdo da requisição codificada em uma aplicação/json é um JSON, então podemos usar json_decode para acessar esses parâmetros.
Se você ler a documentação do Silex, poderá ver como manipular essas requisições, http://silex.sensiolabs.org/doc/cookbook/json_request_body.html
Neste artigo, não vamos encapsular esse código em um provedor de serviço. Ok, isso não é realmente um provedor de serviço (porque não provê nenhum serviço). Ele só muda a requisição (quando temos a aplicação/json) sem copiar e colar o mesmo código em cada projeto.
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') ]); });
O provedor de serviço é muito simples.
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'); } }
Você pode ver o código completo no meu GitHub e também no Packagist.
***
Gonzalo Ayuso faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: http://gonzalo123.com/2015/02/02/handling-angularjs-post-requests-with-a-silex-backend/