Back-End

4 mar, 2015

Manipulando requisições POST no AngularJS com backend Silex

Publicidade

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/