# API Reference - PG-API
> Documentação completa dos endpoints da API PG-API.
---
## 📌 Base URL
```
http://localhost:8580
```
---
## 🔐 Autenticação
A API utiliza autenticação via **API Key** nos headers.
### Headers Requeridos
| `X-API-Key` | Sua API key | `sk_test_123456789` |
| `Authorization` | Alternativa (Bearer) | `Bearer sk_test_123456789` |
### Exemplo
```bash
curl http://localhost:8580/v1/account \
-H "X-API-Key: sk_test_123456789"
```
---
## 📊 Resposta Padrão
Todas as respostas seguem o formato:
```json
{
"success": true,
"data": { ... },
"error": null,
"metadata": {
"request_id": "uuid",
"execution_time_ms": 42,
"rows_affected": 1,
"instance_id": "acc_001",
"timestamp": "2025-02-16T14:30:00Z"
}
}
```
### Em caso de erro:
```json
{
"success": false,
"data": null,
"error": {
"code": "PERMISSION_DENIED",
"message": "Access denied to database 'production'"
},
"metadata": { ... }
}
```
---
## 🏥 Health & Status
### GET `/health`
Health check básico do serviço.
**Autenticação:** Não requerida
**Resposta:**
```json
{
"status": "healthy",
"service": "pg-api",
"version": "0.1.1"
}
```
---
### GET `/v1/status`
Status detalhado do serviço.
**Autenticação:** Requerida
**Resposta:**
```json
{
"instances": 1,
"active_connections": 5,
"status": "operational"
}
```
---
## 📝 Queries
### POST `/v1/query`
Executa uma query SQL única.
**Autenticação:** Requerida
**Request Body:**
```json
{
"database": "mydb",
"query": "SELECT * FROM users WHERE id = $1",
"params": [1],
"options": {
"timeout_ms": 30000
}
}
```
| `database` | string | ✅ | Nome do database |
| `query` | string | ✅ | Query SQL (exatamente 1 statement; `;` empilhado é rejeitado) |
| `params` | array | ❌ | Parâmetros da query (`$1`, `$2`…) |
| `options.timeout_ms` | number | ❌ | Timeout em milissegundos (default 60000, teto 300000) |
| `options.read_only` | boolean | ❌ | Quando `true`, executa em transação `READ ONLY` |
> **Gate SQL (v0.3):** comentários são removidos antes da classificação; `WITH` com `INSERT/UPDATE/DELETE` exige a permissão de escrita correspondente; `COPY`, controle transacional (`BEGIN/COMMIT/...`), comandos de sessão (`SET`, `VACUUM`, …) e funções perigosas (`pg_read_file`, `dblink`, `lo_import`, …) são negados.
**Resposta de Sucesso:**
```json
{
"success": true,
"data": {
"rows": [
{"id": 1, "name": "John Doe", "email": "john@example.com"}
],
"columns": ["id", "name", "email"],
"row_count": 1
},
"error": null,
"metadata": {
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"execution_time_ms": 15,
"rows_affected": 1,
"instance_id": "acc_001",
"timestamp": "2025-02-16T14:30:00Z"
}
}
```
**Exemplo cURL:**
```bash
curl -X POST http://localhost:8580/v1/query \
-H "X-API-Key: sk_test_123456789" \
-H "Content-Type: application/json" \
-d '{
"database": "postgres",
"query": "SELECT version()"
}'
```
---
### POST `/v1/batch`
Executa múltiplas queries em batch (não atômico; para atomicidade use `/v1/transaction`).
> **v0.3:** máximo de **50 statements** por batch; batch vazio é rejeitado.
**Autenticação:** Requerida
**Request Body:**
```json
[
{
"database": "mydb",
"query": "INSERT INTO users (name) VALUES ($1)",
"params": ["Alice"]
},
{
"database": "mydb",
"query": "INSERT INTO users (name) VALUES ($1)",
"params": ["Bob"]
}
]
```
**Resposta:**
```json
{
"success": true,
"data": [
{
"rows": [],
"columns": [],
"row_count": 0
},
{
"rows": [],
"columns": [],
"row_count": 0
}
],
"error": null,
"metadata": { ... }
}
```
---
### POST `/v1/transaction`
Executa queries em uma transação ACID real (uma conexão, `COMMIT` no sucesso e `ROLLBACK` em qualquer falha).
> **v0.3:** todos os statements devem mirar o **mesmo database**; máximo de **50 statements**.
**Autenticação:** Requerida
**Request Body:** array de `QueryRequest` (mesmo formato de `/v1/query`):
```json
[
{
"database": "mydb",
"query": "UPDATE accounts SET balance = balance - $1 WHERE id = $2",
"params": [100, 1]
},
{
"database": "mydb",
"query": "UPDATE accounts SET balance = balance + $1 WHERE id = $2",
"params": [100, 2]
}
]
}
```
| `database` | string | ✅ | Nome do database |
| `queries` | array | ✅ | Lista de queries |
| `queries[].query` | string | ✅ | Query SQL |
| `queries[].params` | array | ❌ | Parâmetros |
**Resposta:**
```json
{
"success": true,
"data": {
"committed": true,
"results": [
{"rows_affected": 1},
{"rows_affected": 1}
]
},
"error": null,
"metadata": { ... }
}
```
---
## 🗄️ Database Management
### GET `/v1/databases`
Lista todos os databases disponíveis para a conta.
**Autenticação:** Requerida
**Resposta:**
```json
{
"success": true,
"data": {
"databases": ["postgres", "myapp", "analytics"]
},
"error": null,
"metadata": { ... }
}
```
---
### POST `/v1/databases`
Cria um novo database.
**Autenticação:** Requerida<br>
**Permissão:** `CREATE` necessária
**Request Body:**
```json
{
"name": "new_database"
}
```
**Resposta:**
```json
{
"success": true,
"data": {
"created": true,
"name": "new_database"
},
"error": null,
"metadata": { ... }
}
```
---
### DELETE `/v1/databases/{name}`
Remove um database.
**Autenticação:** Requerida<br>
**Permissão:** `DROP` necessária
**Parâmetros URL:**
| `name` | Nome do database |
**Resposta:**
```json
{
"success": true,
"data": {
"dropped": true,
"name": "old_database"
},
"error": null,
"metadata": { ... }
}
```
---
### POST `/v1/databases/{db}/export`
Exporta o database como arquivo PostgreSQL custom-format. O `pg_dump` é
executado no Nexus; o cliente não fornece comando nem caminho remoto.
**Autenticação:** Requerida
**Permissão:** `EXPORT` necessária
Parâmetros opcionais repetidos `exclude_table=public.nome_da_tabela` excluem
tabelas auxiliares do arquivo. Somente identificadores simples do schema
`public` são aceitos. A resposta é `application/octet-stream`.
### POST `/v1/databases/{db}/import`
Restaura um arquivo custom-format enviado no corpo da requisição.
**Autenticação:** Requerida
**Permissão:** `IMPORT` necessária
Use `?clean=true` para solicitar limpeza dos objetos existentes. O Nexus
valida o arquivo com `pg_restore --list` antes da restauração e executa o
restore com `--exit-on-error`, sem aceitar caminhos ou comandos arbitrários.
**Content-Type:** `application/octet-stream`
### GET `/v1/databases/{db}/tables`
Lista tabelas de um database.
**Autenticação:** Requerida
**Parâmetros URL:**
| `db` | Nome do database |
**Resposta:**
```json
{
"success": true,
"data": {
"tables": ["users", "orders", "products"]
},
"error": null,
"metadata": { ... }
}
```
---
### GET `/v1/databases/{db}/schema`
Retorna o schema de um database.
**Autenticação:** Requerida
**Parâmetros URL:**
| `db` | Nome do database |
**Resposta:**
```json
{
"success": true,
"data": {
"tables": [
{
"name": "users",
"columns": [
{"name": "id", "type": "integer", "nullable": false},
{"name": "name", "type": "varchar", "nullable": false},
{"name": "email", "type": "varchar", "nullable": true}
]
}
]
},
"error": null,
"metadata": { ... }
}
```
---
## 👤 Account Management
### GET `/v1/account`
Retorna informações da conta autenticada.
**Autenticação:** Requerida
**Resposta:**
```json
{
"success": true,
"data": {
"id": "acc_001",
"name": "Production Account",
"role": "owner",
"rate_limit": 1000,
"max_connections": 50,
"databases": ["postgres", "mydb"],
"created_at": "2025-01-01T00:00:00Z",
"last_used": "2025-02-16T14:30:00Z"
},
"error": null,
"metadata": { ... }
}
```
---
### GET `/v1/account/usage`
Retorna estatísticas de uso da conta.
**Autenticação:** Requerida
**Resposta:**
```json
{
"success": true,
"data": {
"requests_today": 1523,
"requests_this_month": 45231,
"active_connections": 5,
"rate_limit_remaining": 847,
"rate_limit_reset": "2025-02-16T15:00:00Z"
},
"error": null,
"metadata": { ... }
}
```
---
## 📖 Documentação
### GET `/docs`
Interface Swagger UI com documentação interativa.
**Autenticação:** Não requerida
---
### GET `/openapi.json`
Especificação OpenAPI 3.0 em JSON.
**Autenticação:** Não requerida
---
## ❌ Códigos de Erro
| `UNAUTHORIZED` | 401 | API key inválida ou ausente |
| `PERMISSION_DENIED` | 403 | Sem permissão para a operação |
| `RATE_LIMITED` | 429 | Limite de requisições excedido |
| `CONNECTION_ERROR` | 500 | Erro de conexão com PostgreSQL |
| `QUERY_ERROR` | 400 | Erro na query SQL (a `message` traz o SQLSTATE) |
| `STATEMENT_TIMEOUT` | 408 | Query excedeu o tempo limite |
| `DATABASE_NOT_FOUND` | 404 | Database não existe |
| `TIMEOUT` | 408 | Query excedeu o tempo limite |
| `INTERNAL_ERROR` | 500 | Erro interno do servidor |
### Diagnóstico dos erros do PostgreSQL
Erros devolvidos pelo PostgreSQL preservam o diagnóstico original na `message`:
SQLSTATE, `detail` e `hint`. Isso vale para a query, para os comandos
`BEGIN`/`SET LOCAL`/`COMMIT` e para o encerramento de sessões transacionais:
```json
{
"success": false,
"data": null,
"error": {
"code": "QUERY_ERROR",
"message": "there is no unique or exclusion constraint matching the ON CONFLICT specification (SQLSTATE 42P10)",
"details": null
},
"metadata": { "request_id": "uuid", "execution_time_ms": 1 }
}
```
Quando a mensagem original não estiver disponível, o texto continua sendo
`db error` — trate esse valor como diagnóstico incompleto, nunca como causa raiz.
### Higiene das conexões do pool
Toda query roda dentro da própria transação, e a conexão **só** volta ao pool
quando o encerramento (`COMMIT`/`ROLLBACK`) é confirmado. Se o cliente
desconectar no meio da query, a conexão é descartada — ela nunca é reciclada em
estado desconhecido (`idle in transaction` / transação abortada).
### Headers de Rate Limit
Quando rate limiting está ativo:
| `X-RateLimit-Limit` | Limite total de requisições |
| `X-RateLimit-Remaining` | Requisições restantes |
| `X-RateLimit-Reset` | Timestamp de reset do limite |
---
## 🔗 Exemplos Completos
Veja exemplos em várias linguagens em [`examples/`](../examples/).