497 lines
9.7 KiB
Markdown
497 lines
9.7 KiB
Markdown
# Endpoints e APIs - Documentação Técnica
|
|
|
|
## Visão Geral
|
|
|
|
O aplicativo utiliza uma API REST para comunicação com o servidor, implementando autenticação JWT e endpoints específicos para gerenciamento de entregas, roteirização e sincronização de dados.
|
|
|
|
## Configuração Base
|
|
|
|
### URL Base
|
|
```typescript
|
|
const API_BASE_URL = process.env.API_BASE_URL || 'https://api.example.com'
|
|
```
|
|
|
|
### Timeout
|
|
```typescript
|
|
const API_TIMEOUT = 10000; // 10 segundos
|
|
```
|
|
|
|
### Headers Padrão
|
|
```typescript
|
|
const defaultHeaders = {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
```
|
|
|
|
## Endpoints de Autenticação
|
|
|
|
### 1. Login
|
|
**Endpoint**: `POST /auth/login`
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"username": "string",
|
|
"password": "string"
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Login realizado com sucesso",
|
|
"data": {
|
|
"access_token": "jwt_token_here",
|
|
"user": {
|
|
"id": 1,
|
|
"username": "string",
|
|
"sellerId": 1,
|
|
"name": "string",
|
|
"storeId": "string",
|
|
"email": "string"
|
|
}
|
|
},
|
|
"timestamp": "2024-01-01T00:00:00.000Z",
|
|
"statusCode": 200
|
|
}
|
|
```
|
|
|
|
**Implementação**:
|
|
```typescript
|
|
async login(username: string, password: string): Promise<User> {
|
|
const response = await fetch(`${API_BASE_URL}/auth/login`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ username, password })
|
|
});
|
|
|
|
const data = await response.json();
|
|
if (!data.success) throw new Error(data.message);
|
|
|
|
await this.setToken(data.data.access_token);
|
|
await this.saveUserData(data.data.user);
|
|
return data.data.user;
|
|
}
|
|
```
|
|
|
|
### 2. Logout
|
|
**Endpoint**: `POST /auth/logout`
|
|
|
|
**Headers**:
|
|
```typescript
|
|
{
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Logout realizado com sucesso",
|
|
"data": null,
|
|
"timestamp": "2024-01-01T00:00:00.000Z",
|
|
"statusCode": 200
|
|
}
|
|
```
|
|
|
|
## Endpoints de Entregas
|
|
|
|
### 1. Listar Entregas
|
|
**Endpoint**: `GET /v1/driver/deliveries`
|
|
|
|
**Headers**:
|
|
```typescript
|
|
{
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Entregas carregadas com sucesso",
|
|
"data": [
|
|
{
|
|
"outId": 12345,
|
|
"customerId": 67890,
|
|
"customerName": "João Silva",
|
|
"street": "Rua das Flores",
|
|
"streetNumber": "123",
|
|
"neighborhood": "Centro",
|
|
"city": "São Paulo",
|
|
"state": "SP",
|
|
"zipCode": "01234-567",
|
|
"customerPhone": "(11) 99999-9999",
|
|
"lat": -23.5505,
|
|
"lng": -46.6333,
|
|
"latFrom": "-23.5505",
|
|
"lngFrom": "-46.6333",
|
|
"deliverySeq": 1,
|
|
"routing": 1,
|
|
"status": "pending",
|
|
"outDate": "2024-01-01T10:00:00.000Z",
|
|
"notes": "Observações da entrega"
|
|
}
|
|
],
|
|
"timestamp": "2024-01-01T00:00:00.000Z",
|
|
"statusCode": 200
|
|
}
|
|
```
|
|
|
|
### 2. Obter Entrega Específica
|
|
**Endpoint**: `GET /v1/driver/deliveries/{outId}`
|
|
|
|
**Parâmetros**:
|
|
- `outId`: ID da entrega
|
|
|
|
**Response**: Mesmo formato do item individual da lista de entregas
|
|
|
|
### 3. Notas Fiscais do Cliente
|
|
**Endpoint**: `GET /v1/driver/deliveries/{outId}/customer/{customerId}`
|
|
|
|
**Parâmetros**:
|
|
- `outId`: ID da entrega
|
|
- `customerId`: ID do cliente
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Notas fiscais carregadas",
|
|
"data": [
|
|
{
|
|
"invoiceId": "NF001",
|
|
"transactionId": 12345,
|
|
"customerName": "João Silva",
|
|
"invoiceValue": 150.00,
|
|
"status": "pending",
|
|
"itens": [
|
|
{
|
|
"productName": "Produto A",
|
|
"quantity": 2,
|
|
"unitValue": 75.00
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### 4. Criar/Concluir Entrega
|
|
**Endpoint**: `POST /v1/delivery/create`
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"outId": 12345,
|
|
"transactionId": 67890,
|
|
"receiverDoc": "12345678901",
|
|
"receiverName": "João Silva",
|
|
"lat": -23.5505,
|
|
"lng": -46.6333,
|
|
"broken": false,
|
|
"devolution": false,
|
|
"reasonDevolution": null,
|
|
"deliveryImages": ["url1", "url2"],
|
|
"userId": 1
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Entrega criada com sucesso",
|
|
"data": {
|
|
"deliveryId": "del_12345",
|
|
"status": "delivered",
|
|
"timestamp": "2024-01-01T10:00:00.000Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
### 5. Atualizar Status da Entrega
|
|
**Endpoint**: `POST /v1/driver/delivery/status`
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"outId": 12345,
|
|
"customerId": 67890,
|
|
"status": "in_progress",
|
|
"lat": -23.5505,
|
|
"lng": -46.6333,
|
|
"notes": "Observações opcionais"
|
|
}
|
|
```
|
|
|
|
## Endpoints de Roteirização
|
|
|
|
### 1. Enviar Ordem de Roteamento
|
|
**Endpoint**: `POST /v1/driver/routing`
|
|
|
|
**Request Body**:
|
|
```json
|
|
[
|
|
{
|
|
"outId": 12345,
|
|
"customerId": 67890,
|
|
"deliverySeq": 1,
|
|
"lat": -23.5505,
|
|
"lng": -46.6333
|
|
},
|
|
{
|
|
"outId": 12346,
|
|
"customerId": 67891,
|
|
"deliverySeq": 2,
|
|
"lat": -23.5506,
|
|
"lng": -46.6334
|
|
}
|
|
]
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Roteamento enviado com sucesso",
|
|
"data": {
|
|
"routingId": "route_12345",
|
|
"totalDeliveries": 2,
|
|
"estimatedTime": "2h30m",
|
|
"totalDistance": "45.2km"
|
|
}
|
|
}
|
|
```
|
|
|
|
## Endpoints de Geolocalização
|
|
|
|
### 1. Obter Coordenadas por Endereço
|
|
**Endpoint**: `GET /v1/geolocation/google`
|
|
|
|
**Query Parameters**:
|
|
- `address`: Endereço
|
|
- `addressNumber`: Número
|
|
- `neighborhood`: Bairro
|
|
- `city`: Cidade
|
|
- `state`: Estado
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Coordenadas obtidas",
|
|
"data": [
|
|
{
|
|
"latitude": -23.5505,
|
|
"longitude": -46.6333,
|
|
"formatted_address": "Rua das Flores, 123 - Centro, São Paulo - SP",
|
|
"accuracy": "high"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Endpoints de Upload
|
|
|
|
### 1. Upload de Imagens
|
|
**Endpoint**: `POST /api/v1/base/send-image`
|
|
|
|
**Content-Type**: `multipart/form-data`
|
|
|
|
**Form Data**:
|
|
- `files`: Arquivos de imagem
|
|
- `transactionId`: ID da transação
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Imagens enviadas com sucesso",
|
|
"data": [
|
|
{
|
|
"url": "https://api.example.com/images/image1.jpg",
|
|
"transactionId": 12345
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Tratamento de Erros
|
|
|
|
### Códigos de Status HTTP
|
|
|
|
- **200**: Sucesso
|
|
- **400**: Erro de validação
|
|
- **401**: Não autorizado (token expirado)
|
|
- **403**: Acesso negado
|
|
- **404**: Recurso não encontrado
|
|
- **500**: Erro interno do servidor
|
|
|
|
### Formato de Erro
|
|
```json
|
|
{
|
|
"success": false,
|
|
"message": "Descrição do erro",
|
|
"data": null,
|
|
"timestamp": "2024-01-01T00:00:00.000Z",
|
|
"statusCode": 400
|
|
}
|
|
```
|
|
|
|
### Tratamento de Erros no Cliente
|
|
```typescript
|
|
try {
|
|
const response = await fetch(endpoint, options);
|
|
|
|
if (response.status === 401) {
|
|
// Token expirado - redirecionar para login
|
|
if (onUnauthorized) onUnauthorized();
|
|
throw new Error('Sessão expirada. Faça login novamente.');
|
|
}
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json();
|
|
throw new Error(errorData.message || 'Erro na requisição');
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data.data;
|
|
} catch (error) {
|
|
console.error('Erro na requisição:', error);
|
|
throw error;
|
|
}
|
|
```
|
|
|
|
## Implementação de Retry e Timeout
|
|
|
|
### Timeout de Requisições
|
|
```typescript
|
|
const controller = new AbortController();
|
|
const timeoutId = setTimeout(() => controller.abort(), API_TIMEOUT);
|
|
|
|
try {
|
|
const response = await fetch(endpoint, {
|
|
...options,
|
|
signal: controller.signal
|
|
});
|
|
clearTimeout(timeoutId);
|
|
return response;
|
|
} catch (error) {
|
|
if (error.name === 'AbortError') {
|
|
throw new Error('Tempo limite excedido');
|
|
}
|
|
throw error;
|
|
}
|
|
```
|
|
|
|
### Retry Automático
|
|
```typescript
|
|
async function requestWithRetry<T>(
|
|
requestFn: () => Promise<T>,
|
|
maxRetries: number = 3
|
|
): Promise<T> {
|
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
try {
|
|
return await requestFn();
|
|
} catch (error) {
|
|
if (attempt === maxRetries) throw error;
|
|
|
|
// Aguardar antes da próxima tentativa
|
|
await new Promise(resolve =>
|
|
setTimeout(resolve, Math.pow(2, attempt) * 1000)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Cache e Otimização
|
|
|
|
### Cache de Requisições
|
|
```typescript
|
|
class ApiCache {
|
|
private cache = new Map<string, { data: any; timestamp: number }>();
|
|
private TTL = 5 * 60 * 1000; // 5 minutos
|
|
|
|
get(key: string): any | null {
|
|
const cached = this.cache.get(key);
|
|
if (!cached) return null;
|
|
|
|
if (Date.now() - cached.timestamp > this.TTL) {
|
|
this.cache.delete(key);
|
|
return null;
|
|
}
|
|
|
|
return cached.data;
|
|
}
|
|
|
|
set(key: string, data: any): void {
|
|
this.cache.set(key, {
|
|
data,
|
|
timestamp: Date.now()
|
|
});
|
|
}
|
|
}
|
|
```
|
|
|
|
### Compressão de Dados
|
|
```typescript
|
|
// Para dados grandes, implementar compressão
|
|
const compressedData = await compress(JSON.stringify(data));
|
|
```
|
|
|
|
## Monitoramento e Logs
|
|
|
|
### Log de Requisições
|
|
```typescript
|
|
function logRequest(endpoint: string, method: string, duration: number) {
|
|
console.log(`API Request: ${method} ${endpoint} - ${duration}ms`);
|
|
}
|
|
```
|
|
|
|
### Métricas de Performance
|
|
```typescript
|
|
interface ApiMetrics {
|
|
totalRequests: number;
|
|
successRate: number;
|
|
averageResponseTime: number;
|
|
errorCount: number;
|
|
}
|
|
```
|
|
|
|
## Considerações para Sincronização Offline
|
|
|
|
### 1. Endpoints para Sincronização
|
|
```typescript
|
|
// Endpoint para sincronização completa
|
|
POST /v1/sync/full
|
|
|
|
// Endpoint para sincronização incremental
|
|
POST /v1/sync/incremental
|
|
|
|
// Endpoint para sincronização seletiva
|
|
POST /v1/sync/selective
|
|
```
|
|
|
|
### 2. Controle de Versão
|
|
```typescript
|
|
// Headers para controle de versão
|
|
{
|
|
'If-Modified-Since': '2024-01-01T00:00:00.000Z',
|
|
'If-None-Match': 'etag_value'
|
|
}
|
|
```
|
|
|
|
### 3. Sincronização em Lotes
|
|
```typescript
|
|
// Enviar múltiplas entregas de uma vez
|
|
POST /v1/delivery/create-batch
|
|
```
|
|
|
|
Esta documentação fornece uma visão completa dos endpoints utilizados pelo aplicativo, servindo como base para implementar melhorias na sincronização offline e otimizações de performance.
|