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/




