API Server v6.4 – Documentação de Métodos (Endpoints)
Visão geral
-----------
A versão 6.4 do servidor expõe endpoints REST organizados em 4 grupos:
1) Administração / OpenAPI (importação e metadados)
2) Swagger & utilitários (docs, versão, teste)
3) CRUD genérico por recurso (tabelas autorizadas)
4) Arquivos (BLOB em HFSQL)
Autenticação
------------
- Autenticação normal (obrigatória para quase todos os endpoints):
- API Key: header `X-API-Key: <sua-chave>`
- ou Bearer/JWT: header `Authorization: Bearer <token>`
- Chave Admin (apenas para endpoints de administração):
- Header adicional `X-API-Key: <SUA_CHAVE_ADMIN_FORTE>` configurada por `Enable_Admin_OpenAPI()`
- Autorização por tabela/método (v6.1):
- Definida em `api_allowed_tables.json`, controla quais métodos cada recurso pode usar.
Padrões de cabeçalhos
---------------------
- `Content-Type: application/json` para POST/PATCH com JSON.
- `Accept: application/json` recomendado para respostas JSON.
- Para upload de arquivo BLOB, enviar JSON Base64 (ver seção Arquivos).
Códigos de erro (geral)
-----------------------
- 200 OK
- 201 Created (POST bem sucedido)
- 204 No Content (DELETE sem corpo)
- 400 Bad Request (parâmetros/JSON inválidos)
- 401 Unauthorized (sem autenticação)
- 403 Forbidden (método não autorizado, escopo insuficiente ou admin key inválida)
- 404 Not Found (recurso/rota/arquivo não encontrado)
- 409 Conflict (violação de PK/índice; conforme cenário)
- 500 Import failed / erro interno
====================================================================
1) Endpoints de Administração / OpenAPI (v6.4)
====================================================================
POST /api/v6/admin/openapi/import
---------------------------------
Importa um documento OpenAPI/Swagger e gera automaticamente:
- tabelas HFSQL (com base em components.schemas)
- autorização `api_allowed_tables.json`
- metadados `openapi_client_meta.json` (enums, polimorfismo, descrições)
Segurança:
- Requer autenticação normal (API Key ou Bearer)
- Requer header extra: `X-API-Key: <SUA_CHAVE_ADMIN_FORTE>`
Body (3 formatos aceitos):
A) JSON com URL remota:
{
"openapi_url": "https://seu.dominio/openapi.json"
}
B) JSON com o documento diretamente:
{
"openapi_json": "{ ... JSON OpenAPI ... }"
}
C) JSON bruto do OpenAPI no body (sem wrapper).
Resposta de sucesso (200):
{ "ok": true, "message": "OpenAPI importado com sucesso (v6.4). Recursos recarregados." }
Erros comuns:
- 403 Forbidden: admin import desligado ou X-API-Key inválida
- 400 Bad Request: URL inválida / JSON ausente / documento sem components.schemas
- 500 Import failed: erro no parser/geração (verificar logs)
GET /api/v6/admin/openapi/meta
------------------------------
Retorna o conteúdo de `openapi_client_meta.json`, gerado após a importação.
Inclui informações de enum, polimorfismo (oneOf/anyOf/discriminator) e descrição de campos.
Segurança:
- Requer autenticação normal (API Key ou Bearer)
- Chave Admin não é obrigatória (configurável)
Resposta (200, application/json):
{
"resources": [
{
"name": "pedidos",
"pk": "id",
"poly": "discriminator:tipo|...",
"fields": [
{"name":"status","type":"string","enum":"NOVO,PAGO,CANCELADO","descr":"..."}
]
}
],
"debug": ["Swagger 2.0 detectado – conversão básica aplicada.", "..."]
}
====================================================================
2) Swagger & Utilitários
====================================================================
GET /api/v6/docs
----------------
Exibe a UI do Swagger (documentação interativa).
- Pode exigir autenticação/assinar o token conforme sua configuração.
GET /api/v6/swagger.json
------------------------
Retorna o documento OpenAPI que representa os endpoints publicados (auto-gerado).
GET /api/v6/version
-------------------
Retorna informações do servidor (versão, hora de inicialização, recursos publicados).
Exemplo de resposta:
{
"version": "6.4",
"serverUp": "2025-08-15T10:10:10Z",
"tables": ["pedidos", "pedidos_itens", ...]
}
GET /api/v6/test
----------------
Endpoint de saúde (health check). Útil para monitoramento/self-test.
====================================================================
3) CRUD Genérico (recursos/tabelas autorizadas)
====================================================================
Observações importantes:
- O nome do recurso normalmente corresponde ao nome da tabela (em minúsculas).
- A PK padrão é "id" (autoID). Pode ser detectada automaticamente pela análise quando diferente.
- Autorização por método é aplicada: GET/POST/PATCH/DELETE/HEAD/COUNT/EXPORT conforme `api_allowed_tables.json`.
- Filtros, ordenação e paginação podem ser passados via query string (ver abaixo).
Listar (coleção)
GET /api/v6/{recurso}
---------------------
Query params suportados (implementação típica):
- select=campo1,campo2,... -> projeção
- where=expressao -> filtro simples (ex: where=status='PAGO')
- order=campo1,-campo2 -> ordenação (desc com prefixo "-")
- limit=50 -> máximo de registros
- offset=0 -> deslocamento para paginação
- q=texto -> busca rápida (quando disponível)
Resposta (200): JSON array com os registros selecionados.
Obter por ID
GET /api/v6/{recurso}/{id}
--------------------------
Resposta (200): JSON do registro.
Erros: 404 se não encontrado.
Cabeçalhos
HEAD /api/v6/{recurso}/{id}
---------------------------
Retorna apenas cabeçalhos (útil para verificar existência/etag).
Criar
POST /api/v6/{recurso}
----------------------
Body (application/json): objeto com os campos do registro.
Resposta (201 ou 200): objeto criado (pode retornar o ID gerado) ou JSON com { "id": <novo_id> }.
Atualizar (parcial)
PATCH /api/v6/{recurso}/{id}
----------------------------
Body (application/json): somente campos a atualizar.
Resposta (200): objeto atualizado ou { "ok": true }.
Excluir
DELETE /api/v6/{recurso}/{id}
-----------------------------
Resposta (204): sem corpo (ou { "ok": true }).
Contagem
GET /api/v6/{recurso}/count
---------------------------
Retorna a contagem total (considerando filtros aplicáveis via query string).
Resposta (200): { "count": 123 }
Exportação CSV
GET /api/v6/{recurso}/export.csv
--------------------------------
Exporta o resultado (com filtros) em CSV.
Headers: `Content-Type: text/csv`
Exemplo (Pedidos)
-----------------
1) Criar pedido
POST /api/v6/pedidos
{
"cliente_id": 1,
"data": "2025-08-15T12:00:00",
"status": "NOVO",
"valor_total": 0
}
2) Inserir item
POST /api/v6/pedidos_itens
{
"pedido_id": 10,
"produto_id": 2001,
"quantidade": 2,
"valor_unit": 50.0
}
3) Recalcular total (quando houver hooks/lambdas configurados)
PATCH /api/v6/pedidos/10
{ "status": "PAGO" }
====================================================================
4) Arquivos (BLOB em HFSQL)
====================================================================
Upload de Arquivo (BLOB)
POST /api/v6/files
------------------
Body (application/json):
{
"table": "pedidos",
"record_id": 10,
"field": "contrato_blob",
"filename": "contrato.pdf",
"mimetype": "application/pdf",
"content_base64": "<BASE64_DO_ARQUIVO>"
}
Resposta (200): { "ok": true, "file_id": "uuid-ou-interno" }
Download de Arquivo
GET /api/v6/files/{file_id}
---------------------------
Resposta (200): corpo binário ou JSON com metadados + stream
Headers: `Content-Type` conforme `mimetype` armazenado.
Excluir Arquivo
DELETE /api/v6/files/{file_id}
------------------------------
Resposta (204): sem corpo (ou { "ok": true }).
====================================================================
Autorização por Tabela/Método (api_allowed_tables.json)
====================================================================
Formato v6.1 (recomendado)
--------------------------
{
"wildcard": false,
"default": { "methods": ["GET"], "readScope": "*:read" },
"tables": {
"pedidos": { "methods": ["GET","POST"], "readScope":"pedidos:read", "writeScope":"pedidos:write" },
"pedidos_itens": { "methods": ["GET","POST","PATCH","DELETE"] }
}
}
Regras:
- Se "wildcard": true ? todas as tabelas da análise são expostas (cuidado em produção).
- "default.methods" ? métodos liberados quando a tabela não possui regra específica.
- Métodos válidos: GET, POST, PUT, PATCH, DELETE, HEAD, COUNT, EXPORT.
====================================================================
Notas Avançadas (v6.4)
====================================================================
- Importador universal:
- Aceita Swagger 2.0 e OpenAPI 3.0/3.1.
- Converte 2.0 ? 3.x básico (definitions ? components.schemas).
- Resolve $ref com cache e detecção de ciclos.
- Suporta allOf, anyOf, oneOf e discriminator (polimorfismo);
nos casos ambíguos, registra "poly" nos metadados para a UI.
- Captura enums e adiciona em metadados (útil para combos).
- Tipagem HFSQL:
- string/date/date-time/binary, integer/number ? mapeados para tipos nativos.
- arrays/objects: por padrão serializados como TEXT (JSON) na v6.4 (pode customizar).
- Segurança:
- Use HTTPS em produção.
- Restrinja /admin por IP/Firewall + X-API-Key Admin.
- Evite wildcard em produção; defina explicitamente as tabelas e métodos.
- Performance:
- Ajuste índices e FKs conforme necessidade real.
- Use paginação (`limit`/`offset`) em listas grandes.
//———
API Client v6.4 – Documentação de Métodos
=========================================
Visão geral
-----------
A classe **clsApiClientV64** é um *wrapper* moderno para consumir a API Server v6.4.
Ela incorpora o cliente v6.3 e v6.2 internamente para:
- Importar OpenAPI por **URL** ou **JSON bruto** (método Admin)
- Autenticar por **API Key** ou **Bearer/JWT**
- Consumir o **CRUD genérico** com *chain methods* (via `clsApiClientV60`)
- Abrir **Swagger UI** e executar **self-test**
- Suportar **upload/download** de arquivos (BLOB)
- Usar metadados gerados pelo OpenAPI (`openapi_client_meta.json`)
Estrutura
---------
- `clsApiClientV64` ? camada mais nova (helper AdminImportOpenAPI URL/JSON)
- `clsApiClientV63` ? inclui os métodos Admin da v6.3 (import por URL)
- `clsApiClientV62` ? inclui AdminImportOpenAPIFromJSON + GetOpenAPIMeta
- `clsApiClientV60` ? base CRUD/Chain/Files/SelfTest/Swagger
Requisitos
----------
- BaseURL do servidor (`http://host:porta`)
- Autenticação (API Key ou Bearer/JWT) configurada
- Para endpoints admin: `X-API-Key` de **admin** definida no servidor com `Enable_Admin_OpenAPI()`
--------------------------------------------------------------------------------
clsApiClientV64 – Métodos
--------------------------------------------------------------------------------
Constructor(base: string="")
---------------------------
**O que faz:** Instancia o cliente com a URL base opcional.
**Ex.:**
```wl
c is clsApiClientV64("http://localhost:8080")
```
SetBaseURL(u: string)
---------------------
**O que faz:** Define a URL base do servidor.
**Ex.:**
```wl
c.SetBaseURL("http://api.meusistema:8080")
```
SetAuthApiKey(k: string, header: string="X-API-Key")
----------------------------------------------------
**O que faz:** Configura autenticação por **API Key**.
- Parâmetro `header` permite customizar o nome do cabeçalho (default: `X-API-Key`).
**Ex.:**
```wl
c.SetAuthApiKey("MINHA_CHAVE")
// ou se seu servidor usar um header diferente:
c.SetAuthApiKey("MINHA_CHAVE", "x-api-token")
```
SetAuthBearer(tok: string)
--------------------------
**O que faz:** Configura autenticação por **Bearer/JWT**.
- Enviado como `Authorization: Bearer <tok>`.
**Ex.:**
```wl
c.SetAuthBearer("eyJhbGciOi...")
```
SetAdminKey(k: string)
----------------------
**O que faz:** Define a **chave Admin** usada nos endpoints de administração (`/api/v6/admin/...`).
**Ex.:**
```wl
c.SetAdminKey("SUA_CHAVE_ADMIN_FORTE")
```
AdminImportOpenAPI(urlOrJSON: string) : stClientV64Response
-----------------------------------------------------------
**O que faz:** Importa um OpenAPI/Swagger no servidor v6.4 e aciona geração de tabelas, permissões e metadados.
- Se o parâmetro começar com `http://` ou `https://`, tratará como **URL remota**.
- Caso contrário, será considerado **JSON bruto**.
**Retorno:** registro com `status` (HTTP) e `body` (texto da resposta).
**Ex.:**
```wl
// Por URL remota
r is stClientV64Response = c.AdminImportOpenAPI("https://seu.dominio/openapi.json")
Info(r.status + " -> " + r.body)
// Por JSON bruto (carregado de arquivo)
r = c.AdminImportOpenAPI(fLoadText("openapi.json"))
```
Table(res: string) : clsApiQueryV60
-----------------------------------
**O que faz:** Inicia um *query builder* para o recurso/tabela informado.
**Retorna:** objeto `clsApiQueryV60` com métodos de *chain* (Select/Where/Order/Limit/…).
**Ex.:**
```wl
q is clsApiQueryV60 = c.Table("pedidos")
```
OpenSwagger()
-------------
**O que faz:** Abre a UI do Swagger no navegador padrão (URL `/api/v6/docs`).
**Ex.:**
```wl
c.OpenSwagger()
```
SelfTest() : string
-------------------
**O que faz:** Executa um teste rápido de conectividade/saúde (health check) e retorna a resposta textual.
**Ex.:**
```wl
Trace(c.SelfTest())
```
--------------------------------------------------------------------------------
clsApiQueryV60 – Métodos de Chain/CRUD (retornado por Table())
--------------------------------------------------------------------------------
> Observação: estes métodos fazem a chamada HTTP quando você finaliza com `List()`, `Get()`, `Insert...`, `Update...`, `Delete()`, etc.
Select(cols: string) : clsApiQueryV60
-------------------------------------
**O que faz:** Define projeção (colunas a retornar).
**Ex.:**
```wl
c.Table("pedidos").Select("id,data,status,valor_total").List()
```
Where(expr: string) : clsApiQueryV60
------------------------------------
**O que faz:** Define filtro (expressão suportada pelo servidor).
**Ex.:**
```wl
c.Table("pedidos").Where("status='PAGO' AND data>='2025-01-01'").List()
```
Order(expr: string) : clsApiQueryV60
------------------------------------
**O que faz:** Define ordenação (ex.: `campo,-campo2` para DESC).
**Ex.:**
```wl
c.Table("pedidos").Order("data,-id").Limit(50).List()
```
Limit(n: int) : clsApiQueryV60
------------------------------
**O que faz:** Define limite de registros (paginações).
**Ex.:**
```wl
c.Table("pedidos").Limit(20).List()
```
Offset(n: int) : clsApiQueryV60
-------------------------------
**O que faz:** Define deslocamento para paginação.
**Ex.:**
```wl
c.Table("pedidos").Limit(20).Offset(20).List()
```
List() : stClientResponseV60
----------------------------
**O que faz:** Executa a consulta e retorna um array JSON de registros.
**Ex.:**
```wl
r is stClientResponseV60 = c.Table("pedidos").Where("status='NOVO'").List()
IF r.status=200 THEN Trace(r.body)
```
Get(id: string|int) : stClientResponseV60
-----------------------------------------
**O que faz:** Obtém um registro por **ID**.
**Ex.:**
```wl
r is stClientResponseV60 = c.Table("pedidos").Get(10)
```
InsertVariant(v: Variant) : stClientResponseV60
-----------------------------------------------
**O que faz:** Cria um registro usando um **Variant** (campos dinâmicos).
**Ex.:**
```wl
p is Variant
p.cliente_id = 1
p.data = DateToString(Today(), "YYYY-MM-DD") + "T12:00:00"
p.status = "NOVO"
p.valor_total = 0
r is stClientResponseV60 = c.Table("pedidos").InsertVariant(p)
```
Insert(jsonBody: string) : stClientResponseV60
----------------------------------------------
**O que faz:** Cria um registro enviando o **JSON** manualmente.
**Ex.:**
```wl
r is stClientResponseV60 = c.Table("pedidos").Insert('{"cliente_id":1,"status":"NOVO","data":"2025-08-15T12:00:00"}')
```
UpdateVariant(id: any, v: Variant) : stClientResponseV60
--------------------------------------------------------
**O que faz:** Atualiza parcialmente um registro por **ID** via `PATCH`.
**Ex.:**
```wl
u is Variant
u.status = "PAGO"
r is stClientResponseV60 = c.Table("pedidos").UpdateVariant(10, u)
```
Update(id: any, jsonBody: string) : stClientResponseV60
-------------------------------------------------------
**O que faz:** Atualiza parcialmente um registro por **ID** enviando o **JSON** manualmente.
**Ex.:**
```wl
r is stClientResponseV60 = c.Table("pedidos").Update(10, '{"status":"PAGO"}')
```
Delete(id: any) : stClientResponseV60
-------------------------------------
**O que faz:** Exclui um registro por **ID**.
**Ex.:**
```wl
r is stClientResponseV60 = c.Table("pedidos").Delete(10)
```
Count() : stClientResponseV60
-----------------------------
**O que faz:** Retorna a contagem de registros considerando filtros.
**Ex.:**
```wl
r is stClientResponseV60 = c.Table("pedidos").Where("status='NOVO'").Count()
```
ExportCSV() : stClientResponseV60
---------------------------------
**O que faz:** Exporta a consulta atual como CSV.
**Ex.:**
```wl
r is stClientResponseV60 = c.Table("pedidos").Where("status='PAGO'").ExportCSV()
IF r.status=200 THEN fSaveText("pedidos_pago.csv", r.body)
```
--------------------------------------------------------------------------------
Arquivos (BLOB) – via clsApiClientV60
--------------------------------------------------------------------------------
UploadFile(localPath: string, table: string, recordID: any, field: string) : stClientResponseV60
------------------------------------------------------------------------------------------------
**O que faz:** Faz upload de arquivo (convertendo para Base64) e armazena no campo **BLOB**.
**Ex.:**
```wl
r is stClientResponseV60 = c.V63.V62.V60.UploadFile("C:\docs\contrato.pdf", "pedidos", 10, "contrato_blob")
```
DownloadFile(table: string, recordID: any, field: string, saveAsPath: string) : stClientResponseV60
---------------------------------------------------------------------------------------------------
**O que faz:** Faz download do arquivo BLOB do registro/campo e salva em disco.
**Ex.:**
```wl
r is stClientResponseV60 = c.V63.V62.V60.DownloadFile("pedidos", 10, "contrato_blob", "C:\tmp\contrato.pdf")
```
--------------------------------------------------------------------------------
Dicas e Boas Práticas
--------------------------------------------------------------------------------
- Sempre defina **BaseURL** e método de **autenticação** antes de chamar os endpoints.
- Para endpoints **Admin**, lembre-se de setar **SetAdminKey()**.
- Prefira `InsertVariant/UpdateVariant` para montar objetos de forma tipada no WL.
- Use `openapi_client_meta.json` para auto-montar **combos de enum** e para orientar a UI em casos com **oneOf/anyOf**.
- Trate respostas: verifique `status` (200, 201, 204, 4xx, 5xx) e exiba `body` em caso de erro.
- Faça paginação (`Limit/Offset`) para listas grandes e use `Select` para reduzir payload.
--------------------------------------------------------------------------------
Exemplos Rápidos
--------------------------------------------------------------------------------
1) Listar pedidos pagos (top 20)
```wl
c is clsApiClientV64("http://localhost:8080")
c.SetAuthApiKey("SUA_CHAVE")
r is stClientResponseV60 = c.Table("pedidos")
.Select("id,data,status,valor_total")
.Where("status='PAGO'")
.Order("data,-id")
.Limit(20)
.List()
Trace(r.status + " -> " + r.body)
```
2) Criar pedido e itens
```wl
c is clsApiClientV64("http://localhost:8080")
c.SetAuthApiKey("SUA_CHAVE")
p is Variant
p.cliente_id = 1
p.data = DateToString(Today(), "YYYY-MM-DD") + "T12:00:00"
p.status = "NOVO"
p.valor_total = 0
rp is stClientResponseV60 = c.Table("pedidos").InsertVariant(p)
i1 is Variant
i1.pedido_id = JSONToVariant(rp.body)["id"]
i1.produto_id = 101
i1.quantidade = 2
i1.valor_unit = 50
ri1 is stClientResponseV60 = c.Table("pedidos_itens").InsertVariant(i1)
```
3) Importar OpenAPI via URL e abrir Swagger
```wl
c is clsApiClientV64("http://localhost:8080")
c.SetAuthApiKey("SUA_CHAVE_NORMAL")
c.SetAdminKey("SUA_CHAVE_ADMIN_FORTE")
resp is stClientV64Response = c.AdminImportOpenAPI("https://seu.dominio/openapi.json")
IF resp.status=200 THEN c.OpenSwagger()
```
4) Upload/Download de arquivo BLOB
```wl
c is clsApiClientV64("http://localhost:8080")
c.SetAuthApiKey("SUA_CHAVE")
// Upload
up is stClientResponseV60 = c.V63.V62.V60.UploadFile("C:\docs\contrato.pdf","pedidos",10,"contrato_blob")
// Download
dw is stClientResponseV60 = c.V63.V62.V60.DownloadFile("pedidos",10,"contrato_blob","C:\tmp\contrato.pdf")
```
Fim.
//———
API v6.4 – Guia Prático com Exemplos
====================================
Escopo
------
Exemplos completos (server + client + HTTP) usando as tabelas **pedidos** e **pedidos_itens**:
- Criar pedido e itens
- Consultar pedido e itens
- Alterar quantidade de item e recalcular total
- Excluir item
- Listar, contar e exportar
- Upload/Download de arquivo (BLOB) vinculado ao pedido
- Boas práticas e erros comuns
Pré-requisitos
--------------
1) Servidor iniciado com a v6.4:
```wl
Init_Server_v64()
Enable_Admin_OpenAPI("SUA_CHAVE_ADMIN_FORTE")
```
2) OpenAPI importado (pelo menos o `openapi_sample_pedidos.json` do pacote) para gerar `pedidos` e `pedidos_itens`.
3) `api_allowed_tables.json` autoriza os métodos usados nos exemplos.
Estrutura (modelo sugerido)
---------------------------
- **pedidos**: id (PK), cliente_id, data (datetime), status (enum: NOVO,PAGO,CANCELADO), valor_total (number).
- **pedidos_itens**: id (PK), pedido_id (FK), produto_id, quantidade, valor_unit (number).
============================================================
A) Exemplos com o Client (WLanguage) – clsApiClientV64
============================================================
1) Criar um pedido e adicionar itens
------------------------------------
```wl
c is clsApiClientV64("http://localhost:8080")
c.SetAuthApiKey("SUA_CHAVE")
// 1) Pedido
pedido is Variant
pedido.cliente_id = 1
pedido.data = DateToString(Today(), "YYYY-MM-DD") + "T12:00:00"
pedido.status = "NOVO"
pedido.valor_total = 0
rp is stClientResponseV60 = c.Table("pedidos").InsertVariant(pedido)
// Captura o ID criado (o server pode retornar {"id":...} ou o objeto completo)
idPedido is int
IF rp.status=200 OR rp.status=201 THEN
v is variant
IF JSONToVariant(v, rp.body) THEN
IF VariantExists(v,"id") THEN idPedido = v["id"]
END
END
Trace("Pedido criado: " + idPedido)
// 2) Itens
i1 is Variant
i1.pedido_id = idPedido
i1.produto_id = 101
i1.quantidade = 2
i1.valor_unit = 50.00
c.Table("pedidos_itens").InsertVariant(i1)
i2 is Variant
i2.pedido_id = idPedido
i2.produto_id = 102
i2.quantidade = 1
i2.valor_unit = 75.50
c.Table("pedidos_itens").InsertVariant(i2)
```
2) Buscar o pedido e seus itens
-------------------------------
```wl
// Pedido
rPed is stClientResponseV60 = c.Table("pedidos").Get(idPedido)
Trace("Pedido: " + rPed.body)
// Itens
rItens is stClientResponseV60 = c.Table("pedidos_itens").Where("pedido_id="+idPedido).List()
Trace("Itens: " + rItens.body)
```
3) Alterar quantidade de um item e recalcular total
---------------------------------------------------
```wl
// Pegue um item do pedido
arr is variant
JSONToVariant(arr, rItens.body)
idItem is int = arr[1]["id"] // exemplo: 1º item
upd is Variant
upd.quantidade = 3
rUp is stClientResponseV60 = c.Table("pedidos_itens").UpdateVariant(idItem, upd)
Trace("Update item: " + rUp.status + " -> " + rUp.body)
// (Opcional) Recalcular total forçando um PATCH no pedido ou confie no hook do server
recalc is Variant
recalc.status = "NOVO" // apenas para disparar hook, se aplicável
c.Table("pedidos").UpdateVariant(idPedido, recalc)
// Leia o pedido novamente
rPed2 is stClientResponseV60 = c.Table("pedidos").Get(idPedido)
Trace("Pedido após ajuste: " + rPed2.body)
```
4) Excluir um item do pedido
----------------------------
```wl
rDel is stClientResponseV60 = c.Table("pedidos_itens").Delete(idItem)
Trace("Delete item: " + rDel.status)
```
5) Paginação, contagem e exportação
-----------------------------------
```wl
// Lista paginada
rList is stClientResponseV60 = c.Table("pedidos")
.Select("id,data,status,valor_total")
.Where("status='NOVO'")
.Order("data,-id")
.Limit(20).Offset(0)
.List()
// Contagem
rCnt is stClientResponseV60 = c.Table("pedidos").Where("status='NOVO'").Count()
// Export CSV (salva em arquivo)
rCsv is stClientResponseV60 = c.Table("pedidos").Where("status='NOVO'").ExportCSV()
IF rCsv.status=200 THEN fSaveText(fExeDir()+"pedidos_novo.csv", rCsv.body)
```
6) Upload & Download de arquivo (BLOB) no pedido
------------------------------------------------
```wl
// Upload (campo BLOB "contrato_blob" em pedidos)
up is stClientResponseV60 = c.V63.V62.V60.UploadFile("C:\docs\contrato.pdf","pedidos",idPedido,"contrato_blob")
// Download
dw is stClientResponseV60 = c.V63.V62.V60.DownloadFile("pedidos", idPedido, "contrato_blob", fExeDir()+"contrato_"+idPedido+".pdf")
```
============================================================
B) Exemplos HTTP (cURL)
============================================================
1) Criar pedido
---------------
```bash
curl -X POST "http://localhost:8080/api/v6/pedidos" \
-H "Authorization: Bearer <TOKEN>" \
-H "Content-Type: application/json" \
-d '{"cliente_id":1,"data":"2025-08-15T12:00:00","status":"NOVO","valor_total":0}'
```
2) Inserir itens
----------------
```bash
curl -X POST "http://localhost:8080/api/v6/pedidos_itens" \
-H "Authorization: Bearer <TOKEN>" -H "Content-Type: application/json" \
-d '{"pedido_id":<ID_PEDIDO>,"produto_id":101,"quantidade":2,"valor_unit":50.0}'
curl -X POST "http://localhost:8080/api/v6/pedidos_itens" \
-H "Authorization: Bearer <TOKEN>" -H "Content-Type: application/json" \
-d '{"pedido_id":<ID_PEDIDO>,"produto_id":102,"quantidade":1,"valor_unit":75.5}'
```
3) Consultar pedido e itens
---------------------------
```bash
curl -H "Authorization: Bearer <TOKEN>" "http://localhost:8080/api/v6/pedidos/<ID_PEDIDO>"
curl -H "Authorization: Bearer <TOKEN>" "http://localhost:8080/api/v6/pedidos_itens?where=pedido_id=<ID_PEDIDO>"
```
4) Alterar quantidade de um item
--------------------------------
```bash
curl -X PATCH "http://localhost:8080/api/v6/pedidos_itens/<ID_ITEM>" \
-H "Authorization: Bearer <TOKEN>" -H "Content-Type: application/json" \
-d '{"quantidade":3}'
```
5) Excluir item
---------------
```bash
curl -X DELETE "http://localhost:8080/api/v6/pedidos_itens/<ID_ITEM>" \
-H "Authorization: Bearer <TOKEN)"
```
6) Contar e exportar pedidos
----------------------------
```bash
curl -H "Authorization: Bearer <TOKEN>" "http://localhost:8080/api/v6/pedidos/count?where=status='NOVO'"
curl -H "Authorization: Bearer <TOKEN>" "http://localhost:8080/api/v6/pedidos/export.csv?where=status='NOVO'"
```
7) Upload/Download de arquivo (BLOB)
------------------------------------
**Upload** (JSON com Base64):
```bash
curl -X POST "http://localhost:8080/api/v6/files" \
-H "Authorization: Bearer <TOKEN>" -H "Content-Type: application/json" \
-d '{"table":"pedidos","record_id":<ID_PEDIDO>,"field":"contrato_blob","filename":"contrato.pdf","mimetype":"application/pdf","content_base64":"<BASE64>"}'
```
**Download** (usando `file_id` ou endpoint do servidor configurado):
```bash
curl -L -H "Authorization: Bearer <TOKEN>" "http://localhost:8080/api/v6/files/<FILE_ID>" -o contrato_baixado.pdf
```
============================================================
C) Boas Práticas e Erros Comuns
============================================================
- **Autorização por método/tabela**: confirme no `api_allowed_tables.json` que `pedidos` e `pedidos_itens` têm os métodos que você precisa (GET/POST/PATCH/DELETE/COUNT/EXPORT).
- **Recálculo de total**: configure **hooks/lambdas** no servidor para recalcular `valor_total` do pedido sempre que um item for incluído/alterado/excluído.
- **Enum de status**: use os metadados (`openapi_client_meta.json`) para montar combos e validar valores permitidos.
- **Data/hora**: envie `date-time` no padrão ISO (`YYYY-MM-DDTHH:mm:ss`).
- **Paginação**: use `.Limit/.Offset` para coleções grandes e sempre `Select()` para reduzir payload.
- **BLOB**: valide tamanho/mimetype do arquivo do lado do servidor; armazene em **BLOB HFSQL** conforme implementado.
- **Erros**: trate HTTP 400/401/403/404/409/500 e mostre o `body` da resposta para diagnóstico.