# Dados

Bancos, coleções e registros com esquemas e regras, por uma única porta REST/JSON.

URL base: `https://data.inovacc.dev`

## Visão geral

Dados é o banco de dados da sua aplicação, servido por uma única porta REST/JSON em `https://data.inovacc.dev`. Você cria **bancos de dados**, dá a eles **coleções** e lê e grava **registros** com chamadas HTTP simples. Uma coleção é tipada, com campos declarados por um esquema, ou livre, contendo documentos JSON sem esquema. Quem pode fazer o quê é decidido em cada requisição, primeiro pelas permissões da credencial e depois, registro a registro, pelas **regras** que a coleção declara.

O problema que ele resolve é manter dados persistentes sem operar um banco de dados: sem servidor, sem pool de conexões, sem ferramenta de migração, sem backups para agendar. Sua aplicação mantém o próprio código e armazena seus dados aqui; onde os dados vivem é decidido pela Inovacc e nunca é exibido. A mesma API atende os seus servidores, as suas páginas web (com uma chave de navegador) e as pessoas autenticadas no seu aplicativo, e um ouvinte em tempo real envia as mudanças conforme elas acontecem.

Use Dados para o estado da aplicação: notas de usuários, pedidos, configurações, catálogos, qualquer coisa com formato de registro. Armazene conteúdo binário grande com [Arquivos](/pt-br/products/files/), consulte o que aconteceu com o [Registro de atividade](/pt-br/products/activity/) e avise outros sistemas com [Eventos](/pt-br/products/events/).

## Conceitos

**Bancos de dados.** Um banco de dados é uma chave que a sua aplicação escolhe, como `shop` ou `crm/v2` (uma `/` é escrita `%2F` em um caminho). Um banco de dados pertence à aplicação cuja credencial o criou; o banco de dados de outra aplicação responde `404`, como se não existisse. Uma credencial no nível da organização enxerga todos os bancos de dados da organização.

**Coleções: com esquema ou livres.** Uma coleção com **esquema** declara até 64 campos, cada um com um tipo: `text`, `integer`, `number`, `bool`, `datetime`, `json`, `relation` (um id de registro em uma coleção `target`) ou `blob` (o SHA-256 de um arquivo no mesmo banco de dados). Um campo pode ser `required`, `unique`, `indexed` ou `fulltext` (em `text`). Uma coleção **livre** não declara nada: cada registro é um documento JSON, consultado por caminho com pontos (`profile.city`), e pode receber um esquema mais tarde, quando todos os documentos se encaixarem nele. Gravar em uma coleção que não existe cria uma coleção livre, quando a sua credencial pode alterar esquemas.

**Registros e versões.** Um registro é `{id, version, created_at, updated_at, ...fields}`. Seu `id` é gerado pelo serviço (`rec_` mais 26 caracteres ordenáveis) ou escolhido por você. Toda alteração aumenta `version` em um; atualizações e exclusões devem enviar `If-Match: <version>`, para que dois escritores nunca se sobrescrevam silenciosamente.

**Regras.** Uma coleção declara cinco regras, `list`, `view`, `create`, `update` e `delete`. Cada uma é `null` (ninguém), `""` (qualquer credencial de servidor da sua organização), `public` (qualquer pessoa, chaves de navegador incluídas), `users` (as pessoas autenticadas da aplicação proprietária, e os servidores) ou uma expressão como `owner = @auth.id`. As regras valem para todas as credenciais, inclusive a de um administrador.

**Credenciais.** Uma **chave secreta** é para servidores. Uma **chave publicável** (`apb_...`) é para páginas web: funciona apenas a partir das origens que a sua aplicação lista e apenas onde uma regra a admite. O **token de acesso** de uma pessoa autenticada carrega apenas permissões de registros e arquivos.

## Como funciona

Toda chamada leva `Authorization: Bearer <credential>`. Não há cabeçalho de organização: a sua organização, e a aplicação, vêm da credencial, e nada em um caminho, consulta ou cabeçalho pode nomear outra. Uma requisição sem credencial válida, ou para um caminho que não é uma rota, recebe um `401` idêntico.

Em cada chamada, o serviço verifica primeiro a permissão da credencial para a ação (leitura, escrita, criação, atualização, exclusão ou alterações de esquema) no banco de dados. Qualquer coisa diferente de "permitir" é `403 forbidden` sem detalhes. Depois a regra da coleção decide por registro: uma listagem devolve apenas os registros que a regra `list` admite; ler um registro que a regra `view` oculta é `404`, igual a um registro inexistente; uma criação verifica os dados novos; uma atualização verifica tanto o registro armazenado quanto os dados novos.

As escritas são versionadas. `POST /records` cria e responde `201` com `ETag: "1"`. `PATCH` altera os campos informados (em uma coleção livre é um JSON merge patch), `PUT` substitui o registro, e `PUT` com `If-None-Match: *` o cria no id que você escolheu. Um `If-Match` errado é `409 version_conflict`; um ausente é `428`.

As listagens aceitam `filter` (`field op value` unidos por `&&` e `||`), `sort`, `limit` (até 200) e um `cursor` opaco, e devolvem `next_cursor` até a última página; `q` pesquisa os campos `fulltext`. Um **lote** aplica até 100 criações, atualizações e exclusões em uma única transação: todas têm sucesso, ou nenhuma.

Um **ouvinte em tempo real** é um WebSocket em `GET .../collections/{c}/listen`: ele envia `ready` e depois eventos `added`, `modified` e `removed` para os registros que a sua regra permite listar. Toda chamada é registrada no [Registro de atividade](/pt-br/products/activity/).

## Primeiros passos

Você precisa de uma chave secreta com permissão para criar bancos de dados e coleções ([Autenticação](/pt-br/guides/authentication/)).

1. **Crie um banco de dados.** `PUT /v1/databases/notes` sem corpo. A resposta é `201` com `{key, created_at}`; repetir a chamada responde `200`.
2. **Declare uma coleção.** `PUT /v1/databases/notes/collections/items` com os campos `owner` e `body` e as regras (veja [os exemplos](#example)). A resposta é a coleção com `schema_version` 1.
3. **Grave um registro.** `POST .../collections/items/records` com os campos. A resposta é `201` com o registro, seu `id` e `version` 1.
4. **Atualize-o.** `PATCH .../records/{id}` com `If-Match: 1`. A resposta tem `version` 2; enviar `If-Match: 1` de novo resulta em `409 version_conflict`.
5. **Liste.** `GET .../records?filter=owner%20%3D%20%22me%22&limit=10` devolve o seu registro e `next_cursor: null`.

## Casos de uso

**Dados por usuário em um aplicativo web.** Um aplicativo de notas declara uma coleção cujas cinco regras dizem `owner = @auth.id`. A página chama Dados diretamente com o token da pessoa autenticada; cada pessoa lista e edita apenas as próprias notas, e a nota de outra pessoa resulta em `404`. Nenhum código de servidor garante isso: as regras garantem.

**Um catálogo público.** Uma loja online mantém `products` como uma coleção livre com `list` e `view` definidos como `public` e as escritas fechadas. A vitrine a lê do navegador com uma chave publicável; o back office a escreve a partir de um servidor com uma chave secreta.

**Painéis em tempo real.** Uma tela de operações abre um ouvinte em `orders` filtrado pelos pedidos abertos de hoje. Ela executa a consulta após `ready`, depois aplica os eventos `added`, `modified` e `removed` conforme chegam, sem fazer polling.

## Limites e preços

| Limite | Valor |
|---|---|
| Corpo da requisição JSON | 1 MiB |
| Um registro | 900 KiB |
| Um campo `json` | 64 KiB |
| Campos por coleção; coleções por banco de dados | 64; 64 |
| Registros por página | 200 (padrão 50) |
| Operações por lote | 100, em uma única transação |
| Filtro | 2.048 caracteres, 40 valores, profundidade de aninhamento 8 |
| Query string | 16 KiB |
| Busca de texto completo `q` | 16 termos, 256 caracteres |
| Ouvintes por coleção; um evento de ouvinte | 1.000; 512 KiB |
| Taxa | 600 requisições por minuto por titular de credencial, por localização (`429 rate_limited`) |

**Preços:** sob consulta.

## Erros

| Status | Código | O que significa e o que fazer |
|---|---|---|
| 400 | `invalid_body`, `invalid_name`, `unknown_field`, `missing_field`, `invalid_value` | O corpo ou um nome viola as regras; corrija-o. |
| 400 | `record_too_large`, `field_too_large`, `reserved_field` | Reduza o registro; não envie `id`, `version`, `created_at`, `updated_at` em um corpo. |
| 400 | `invalid_schema`, `invalid_rule`, `schema_change_unsupported` | A definição da coleção não é válida, ou um campo foi alterado no lugar. |
| 400 | `invalid_filter`, `invalid_sort`, `invalid_cursor`, `invalid_limit`, `invalid_search` | Corrija a consulta da listagem; recomece sem o cursor. |
| 400 | `invalid_if_match`, `batch_too_large`, `cross_shard_batch` | Confira o cabeçalho ou divida o lote. |
| 401 | `invalid_credentials` | Envie uma credencial válida. |
| 403 | `forbidden` | As permissões da credencial ou a regra da coleção a recusam. |
| 403 | `origin_not_allowed`, `secret_key_in_browser` | Uma chave de navegador vinda de uma origem não listada, ou uma chave secreta em um navegador. |
| 404 | `database_not_found`, `collection_not_found`, `record_not_found` | Não existe, ou você não pode vê-lo. |
| 409 | `version_conflict` | Alguém alterou o registro; leia-o novamente e tente de novo. |
| 409 | `already_exists`, `unique_violation`, `not_empty`, `schema_violation` | O id ou valor já está em uso; esvazie antes de excluir; os documentos não se encaixam no esquema. |
| 412, 428 | `precondition_failed`, `precondition_required` | O registro já existe; envie `If-Match`. |
| 413 | `payload_too_large` | O corpo excede 1 MiB. |
| 429 | `rate_limited`, `too_many_listeners` | Diminua o ritmo; feche os ouvintes de que não precisa. |
| 503 | `service_unavailable` | Tente novamente mais tarde; nada foi gravado. |

## Boas práticas

- **Envie sempre `If-Match`** com a versão que você leu e, em `409 version_conflict`, leia de novo antes de tentar novamente.
- **Feche toda coleção por padrão** e abra-a regra a regra; uma coleção nascida de uma escrita admite qualquer credencial de servidor até que você a restrinja.
- **Nunca coloque uma chave secreta em uma página web**: use uma chave publicável e regras `public` ou `@auth`.
- **Escolha os seus próprios ids de registro** nas importações, para que uma importação repetida não crie nada duas vezes (`409 already_exists`).
- **Use um lote** quando várias escritas precisarem ter sucesso juntas.
- **Indexe os campos em que você filtra e ordena** e siga `next_cursor` em vez de usar páginas grandes.
- **Com um ouvinte, espere por `ready` antes de consultar**, e descarte depois os eventos que não sejam mais novos do que o que a consulta devolveu.

## Relacionados

- [Arquivos](/pt-br/products/files/): conteúdo binário ao lado dos seus registros
- [Registro de atividade](/pt-br/products/activity/): o que foi gravado e por quem
- [Eventos](/pt-br/products/events/): avise outros sistemas sobre uma mudança
- [Autenticação](/pt-br/guides/authentication/), [Erros](/pt-br/guides/errors/), [Limites](/pt-br/guides/limits/)

## Endpoints

- GET /v1/databases
- PUT /v1/databases/{database}
- PUT /v1/databases/{database}/collections/{collection}
- POST /v1/databases/{database}/collections/{collection}/records
- POST /v1/databases/{database}/batch

## Exemplo

```sh
curl -X GET "https://data.inovacc.dev/v1/databases" -H "Authorization: Bearer $INOVACC_API_KEY"
```
