JSON-RPC
JSON-RPC
POST /{prefix}/{database}/jsonrpc chama uma função do PostgreSQL e retorna o resultado como uma
resposta JSON-RPC 2.0. Esta página é a
referência; para um primeiro exemplo funcional veja Início rápido.
1. Requisição
POST /db/my_database/jsonrpc
Authorization: Basic ... (or Bearer <jwt / api token>)
Content-Type: application/json
{"jsonrpc": "2.0", "method": "api.hello_world", "params": {"name": "Alice"}, "id": 1}| Campo | Descrição |
|---|---|
method | Obrigatório. schema.function, no máximo 256 caracteres. Identificadores entre aspas ("my schema"."my fn") são permitidos. O schema é obrigatório: hello_world sozinho é rejeitado com 400. capabilities é um método integrado (seção 5). |
params | Qualquer valor JSON, passado sem alterações à função como seu argumento jsonb. Se ausente ou null, vira {}. Objetos são a convenção; arrays e escalares também funcionam. |
id | Qualquer valor JSON; é copiado para a resposta. Se ausente, a resposta contém "id": null (não há notificações do tipo dispare e esqueça). |
jsonrpc | Por convenção "2.0"; não é validado na entrada, a resposta sempre traz "2.0". |
idempotencyKey | Extensão opcional (seção 7). No máximo 256 caracteres. |
Requisições em lote (um array JSON de chamadas) não são suportadas e retornam 400 — envie uma chamada por requisição HTTP.
2. Resposta
HTTP 200 {"jsonrpc":"2.0","result":{"message":"Hello, Alice!"},"id":1}
HTTP 404 {"jsonrpc":"2.0","error":{"code":-32601,"message":"Function does not exist"},"id":1}Diferentemente do JSON-RPC puro sobre um socket, os erros também definem um status HTTP significativo, para que clientes e proxies possam reagir
sem analisar o corpo. O error.code é 0 a menos que um código JSON-RPC específico se aplique
(-32601 função desconhecida, -32001 permissão negada, -32000 requisição duplicada).
A lista completa está na página Códigos de Erro.
3. Escrevendo uma função
Um método é uma função do PostgreSQL que recebe exatamente um argumento do tipo jsonb
e retorna json ou jsonb. Funções com outras assinaturas não são listadas por
capabilities nem podem ser chamadas.
CREATE OR REPLACE FUNCTION api.find_user(payload jsonb DEFAULT '{}'::jsonb)
RETURNS json LANGUAGE sql STABLE AS $$
SELECT row_to_json(u) FROM (
SELECT id, name FROM app.users WHERE id = (payload->>'id')::int
) u;
$$;
GRANT USAGE ON SCHEMA api TO web_user;
GRANT EXECUTE ON FUNCTION api.find_user(jsonb) TO web_user;- Valor de retorno. O resultado JSON é enviado como
result. UmNULLdo SQL (como acima, quando nenhuma linha corresponde) vira"result": null. A função deve retornar JSON válido: um tipo de retornotextfalha com 500 a menos que o texto seja JSON — useto_json('hi'::text)para um resultado do tipo string. - Erros dentro da função.
RAISE EXCEPTIONou qualquer erro SQL aborta a chamada com HTTP 500 e a mensagem genéricaFunction call failed; a mensagem real do PostgreSQL só é escrita no log do servidor, então detalhes do schema não vazam. Informe os erros de negócio esperados (não encontrado, validação) no valor de retorno, por exemplo{"ok": false, "reason": "..."}. - Transações. Cada chamada é executada em uma transação que é confirmada quando a função retorna e revertida em caso de qualquer erro.
- Permissões. A chamada é executada como o papel (role) PostgreSQL autenticado, então
GRANT,REVOKEe Row-Level Security decidem o que quem chama pode fazer. Um papel precisa deUSAGEno schema eEXECUTEna função. O PostgreSQL concedeEXECUTEem novas funções a todos por padrão, então revogue isso (ALTER DEFAULT PRIVILEGES REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC) e mantenha as funções expostas em um schema dedicado — veja Segurança e Autenticação.
4. Descrevendo uma função para clientes e agentes de IA
A primeira linha do comentário da função é a sua descrição; um objeto JSON após --- PARAMS --- descreve os parâmetros
(properties do JSON Schema). Ambos aparecem em capabilities, na especificação OpenAPI e no MCP tools/list:
COMMENT ON FUNCTION api.find_user(jsonb) IS 'Looks up a user by id.
--- PARAMS ---
{"id": {"type": "integer", "description": "User id"}}';Um comentário com JSON malformado após o marcador é ignorado (a função recorre a uma descrição genérica de parâmetros) e nunca quebra a descoberta.
5. Métodos integrados
capabilities
Lista as funções que o papel autenticado pode chamar (EXECUTE e USAGE do schema); schemas do sistema e funções de extensões ficam ocultos.
Cada entrada tem method, description, parameters, http_method, endpoint e
kind (rpc, ou file para funções de arquivo).
{"jsonrpc":"2.0","method":"capabilities","id":1}Fazer login para obter um JWT não é um método JSON-RPC: use POST /{prefix}/{database}/token com credenciais HTTP Basic (seção 6).
O antigo método get_jwt, que recebia a senha em params, foi removido e responde 404 / -32601 com uma indicação do novo endpoint.
6. Autenticação
Toda requisição precisa de um cabeçalho Authorization; uma requisição sem ele é rejeitada com 401 antes de abrir qualquer conexão com o banco de dados.
| Cabeçalho | O que acontece |
|---|---|
Basic <base64(user:password)> | Um pool de conexões autenticado como esse usuário do PostgreSQL. O mais simples; sem tokens. Envie somente via HTTPS. |
Bearer <jwt> | Token de POST /{prefix}/{database}/token (ou do seu próprio provedor de identidade). O PgArachne troca para o papel do token com SET LOCAL ROLE; o papel de serviço precisa de GRANT user TO pgarachne. |
Bearer <api token> | Token de longa duração criado com pgarachne.add_api_token(...), vinculado a um papel. Bom para serviços. |
Obtendo um JWT: POST /{prefix}/{database}/token
Troca um login e senha do PostgreSQL, enviados com autenticação HTTP Basic, por um JWT. As credenciais trafegam no cabeçalho Authorization
— nunca em um corpo JSON — e o endpoint tem sua própria URL, de modo que um proxy reverso pode aplicar limites mais rígidos aos logins sem ler corpos de requisição.
Requer JWT_SECRET; caso contrário retorna 404. Cada tentativa conta para o limite de taxa de login e a resposta nunca pode ser armazenada em cache.
curl -X POST http://localhost:8080/db/my_database/token -u web_user:password
→ {"token":"eyJhbGciOi...","token_type":"Bearer","expires_in":28800}
curl http://localhost:8080/db/my_database/jsonrpc -H "Authorization: Bearer eyJhbGciOi..." \
-H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"capabilities","id":1}'Tentativas falhas têm limite de taxa (HTTP 429). Todos os detalhes, a duração dos tokens e um provedor de identidade externo estão na página Segurança e Autenticação.
7. Idempotência
Adicione "idempotencyKey": "order-42" para tornar uma chamada segura para nova tentativa. A primeira chamada com uma chave é executada normalmente; uma chave repetida é rejeitada
antes de a função executar, com HTTP 409 e -32000 «This request has already been processed». A chave é armazenada na mesma
transação da chamada, então uma chamada que falhou (e foi revertida) pode ser repetida com a mesma chave. As chaves têm namespace por papel.
- Com autenticação por JWT ou token de API funciona sem configuração adicional.
- Com autenticação Basic o próprio usuário grava a chave, então ele precisa de
USAGEno schemapgarachneeINSERTempgarachne.requests(caso contrário a chamada falha com 500Idempotency check failed). - Chaves antigas não são removidas automaticamente — agende
pgarachne.cleanup_idempotency_keys()(veja Limpeza de Chaves de Idempotência).
8. Limites
- Corpo da requisição:
MAX_REQUEST_BYTES(padrão 2 MiB); caso contrário, 413. methodeidempotencyKey: 256 caracteres cada.- Falhas de autenticação:
LOGIN_RATE_LIMIT/LOGIN_RATE_LIMIT_PER_IPporLOGIN_RATE_WINDOW(veja Configuração).
9. Chamando
curl -X POST http://localhost:8080/db/my_database/jsonrpc \
-u web_user:password -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"api.find_user","params":{"id":1},"id":1}'A partir de uma página web use fetch() com o mesmo cabeçalho e corpo; uma página completa para copiar e colar (incluindo SSE e download de arquivos) está em
Início rápido.