Conexões#
O servidor gerencia conexões com bancos de dados e serviços HTTP usados pelos datasources dos relatórios. Conexões são armazenadas com criptografia (quando
ENCRYPTION_KEY está configurado) e testadas automaticamente na criação.
Todos os endpoints de conexão requerem a permissão canSettings.
Em deploys onde outro sistema já gerencia credenciais de banco por tenant, use CONNECTION_REGISTRY_BACKEND=remote. Nesse modo o Sulfite não armazena senhas localmente — cada
connectionRef é resolvido sob demanda no hub da sua infra.
Tipos de conexão#
Database#
Para PostgreSQL e outros bancos via postgres ou postgrest driver:
{
"name": "my-postgres",
"type": "database",
"host": "db.example.com",
"port": 5432,
"database": "mydb",
"username": "user",
"password": "secret",
"ssl": true,
"maxConnections": 5,
"extra": {
"schema": "public",
"authSchema": "sulfite_meta"
}
}
| Campo | Obrigatório | Default | Descrição |
|---|---|---|---|
name | Sim | — | Identificador único da conexão |
type | Sim | — | database |
host | Sim | — | Host do banco |
port | Não | 5432 | Porta |
database | Sim | — | Nome do banco |
username | Sim | — | Usuário |
password | Sim | — | Senha |
ssl | Não | true | Usar SSL |
maxConnections |
Não | 5 |
Tamanho máximo do pool para essa conexão |
extra | Não | — | Configurações extras (driver-specific) |
Campos comuns em extra:
| Campo | Uso |
|---|---|
schema |
Schema padrão usado por datasources SQL e como fallback para autorização por tenant |
authSchema |
Schema específico onde fica sulfite_authorized_users |
Veja Autorização por tenant para o contrato da view sulfite_authorized_users.
HTTP#
Para APIs REST e PostgREST:
{
"name": "my-api",
"type": "http",
"baseUrl": "https://api.example.com",
"defaultHeaders": { "X-Token": "abc123" },
"extra": { "timeout": 30 }
}
| Campo | Obrigatório | Default | Descrição |
|---|---|---|---|
name | Sim | — | Identificador único da conexão |
type | Sim | — | http |
baseUrl | Sim | — | URL base |
defaultHeaders |
Não | — | Headers padrão para todas as requests |
extra | Não | — | Configurações extras |
Sanitização de respostas#
As respostas de GET omitem dados sensíveis:
| Tipo | Campos retornados | Campos omitidos |
|---|---|---|
database |
name
,
type
,
host
,
port
,
database
,
ssl
|
username, password, extra |
http |
name, type, baseUrl |
defaultHeaders, extra |
Criptografia at-rest#
Quando ENCRYPTION_KEY está configurado, os campos sensíveis são criptografados usando AES-256-GCM (via
EnvelopeEncryptor):
| Tipo | Campos criptografados |
|---|---|
database |
password, username, extra |
http | defaultHeaders, extra |
Os dados criptografados são armazenados em um campo _encrypted. Suporta rotação de chave
via ENCRYPTION_KEY_PREV — entradas legadas em texto plano são migradas automaticamente no próximo upsert.
Registry remoto#
Com o backend remoto, o CRUD de conexões pode ficar desligado e o Sulfite apenas resolve connectionRef
no momento da geração:
CONNECTION_REGISTRY_BACKEND=remote
CONNECTION_HUB_URL=https://hub.your-infra.internal
CONNECTION_HUB_TOKEN=<credencial-de-servico>
CONNECTION_HUB_CACHE_TTL_SECONDS=60
CONNECTION_ROUTES_ENABLED=false
O servidor chama GET /internal/tenants/{tenantId}/connections/{connectionRef} no hub e mantém cache curto por tenant/conexão. Use esse modo quando outro sistema é a fonte de verdade para credenciais.
O hub deve retornar um JSON no mesmo formato de ConnectionEntry:
{ "type": "database", "name": "erp", "host": "db.internal", "port": 5432,
"database": "erp", "username": "reader", "password": "secret", "ssl": true }
| Status do hub | Resultado |
|---|---|
200 | Conexão cacheada e usada |
404 | resolveAsync retorna null |
403 | Geração retorna 403 connection_forbidden |
5xx / timeout | Geração retorna 503 connection_unavailable |
Endpoints#
Listar — GET /api/v1/connections#
Query params: ?page=1&limit=20 (paginação opcional)
Resposta 200: Array de conexões sanitizadas.
Detalhes — GET /api/v1/connections/:name#
Resposta 200: Conexão sanitizada.
| Status | Erro | Quando |
|---|---|---|
404 | not_found | Nome não encontrado |
Criar — POST /api/v1/connections#
Body: JSON completo da conexão (veja tipos acima).
Resposta 201: Conexão sanitizada.
| Status | Erro | Quando |
|---|---|---|
400 | missing_name | name ausente |
400 | invalid_type | type inválido |
409 |
already_exists |
Já existe uma conexão com esse nome |
422 |
connection_failed |
Teste de conectividade falhou |
Atualizar — PUT /api/v1/connections/:name#
Body: JSON completo da conexão (o name da URL é usado).
Resposta 200: Conexão sanitizada.
| Status | Erro | Quando |
|---|---|---|
400 | invalid_type | type inválido |
404 | not_found | Nome não encontrado |
422 |
type_change_forbidden |
Tentativa de mudar database ↔ http |
422 |
connection_failed |
Teste de conectividade falhou |
Excluir — DELETE /api/v1/connections/:name#
Resposta 200:
{ "deleted": "my-postgres" }
| Status | Erro | Quando |
|---|---|---|
404 | not_found | Nome não encontrado |
Testar — POST /api/v1/connections/:name/test#
Testa a conectividade sem modificar a conexão armazenada.
Resposta 200:
{ "status": "ok", "latency_ms": 42 }
| Status | Erro | Quando |
|---|---|---|
404 | not_found | Nome não encontrado |
422 |
connection_failed |
Teste falhou (inclui latency_ms) |
Mecanismo de teste:
- Database: executa
SELECT 1 AS pingvia postgres resolver - HTTP: faz
GETna URL base via REST resolver
Exemplo#
# Criar conexão
curl -X POST http://localhost:8080/api/v1/connections \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "producao",
"type": "database",
"host": "db.example.com",
"port": 5432,
"database": "mydb",
"username": "reader",
"password": "s3cret",
"ssl": true
}'
# Listar (sem dados sensíveis)
curl http://localhost:8080/api/v1/connections \
-H "Authorization: Bearer $TOKEN"
# Testar conectividade
curl -X POST http://localhost:8080/api/v1/connections/producao/test \
-H "Authorization: Bearer $TOKEN"