Back-End

21 out, 2015

Construindo um cliente HTTP em PostgreSQL com PL/Python

Publicidade

Não me pergunte por quê, mas eu preciso fazer uma chamada para um servidor HTTP (numa aplicação Silex) a partir de um banco de dados PostgreSQL.

Quero fazer algo assim:

select get('http://localhost:8080?name=Gonzalo')->'hello';

PostgreSQL tem um datatype para json. É realmente muito bacana e permite que se faça uma conexão com seu servidor HTTP em seu banco de dados SQL usando o mesmo datatype.

PostgreSQL também permite criar stored procedures usando diferentes linguagens. A padrão é PL/pgSQL. PL/pgSQL é uma linguagem simples que você pode embedar SQL. Mas nós também podemos usar Python. Com Python, é possível criar facilmente clientes HTTP, por exemplo com urllib2. Isso significa que desenvolveremos nosso cliente HTTP para um banco de dados PostgreSQL de forma bem direta.

CREATE OR REPLACE FUNCTION get(uri character varying)
  RETURNS json AS
$BODY$
import urllib2
 
data = urllib2.urlopen(uri)
 
return data.read()
 
$BODY$
  LANGUAGE plpython2u VOLATILE
  COST 100;
ALTER FUNCTION get(character varying)
  OWNER TO gonzalo;

Ok, isso é um cliente GET, mas também queremos que o cliente POST faça algo assim:

select post('http://localhost:8080', '{"name": "Gonzalo"}'::json)->'hello';

Como você pode ver, eu quero usar a aplicação/json em vez da aplicação/x-www-form-urlencoded para requisitar os parâmetros. Eu escrevi sobre isso há algum tempo. Então, vou criar um endpoint com meu servidor Silex para lidar com as requisições POST:

<?php
include __DIR__ . '/../vendor/autoload.php';
 
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
use G\AngularPostRequestServiceProvider;
 
$app = new Application(['debug' => true]);
 
$app->register(new AngularPostRequestServiceProvider());
 
$app->post('/', function (Application $app, Request $request) {
    return $app->json(['hello' => $request->get('name')]);
});
 
$app->get('/', function (Application $app, Request $request) {
    return $app->json(['hello' => $request->get('name')]);
});
 
$app->run();

E agora só precisamos criar uma stored procedure para enviar as requisições POST

CREATE OR REPLACE FUNCTION post(
    uri character varying,
    paramenters json)
  RETURNS json AS
$BODY$
import urllib2
 
clen = len(paramenters)
req = urllib2.Request(uri, paramenters, {'Content-Type': 'application/json', 'Content-Length': clen})
f = urllib2.urlopen(req)
return f.read()
 
$BODY$
  LANGUAGE plpython2u VOLATILE
  COST 100;
ALTER FUNCTION post(character varying, json)
  OWNER TO gonzalo;

E é isso! Ao menos esse simples script era exatamente o que eu precisava.

***

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/09/21/building-one-http-client-in-postgresql-with-plpython/