Como construir uma API RESTful com Edge Functions e Edge SQL

Este guia demonstra como construir uma API RESTful completa para gerenciamento de tarefas usando Azion Edge Functions e Edge SQL. Você aprenderá a implementar operações CRUD (Create, Read, Update, Delete) completas na edge, fornecendo endpoints de API rápidos e escaláveis globalmente.

Requisitos

Antes de começar, certifique-se de ter:

  • Uma conta na Azion
  • Azion CLI instalada e configurada
  • Node.js versão 18 ou superior
  • Gerenciador de pacotes pnpm instalado
  • Edge SQL habilitado em sua conta Azion
  • Conhecimento básico de JavaScript, APIs REST e SQL
  • Uma instância Edge SQL configurada e funcionando

Primeiros passos

Passo 1: Configure seu ambiente de desenvolvimento

  1. Clone o repositório de exemplo de tarefas RESTful:
Terminal window
git clone https://github.com/egermano/edge-functions-examples.git
cd edge-functions-examples/packages/restful-tasks
  1. Instale as dependências do projeto:
Terminal window
pnpm install
  1. Revise a estrutura do projeto para entender a implementação:
Terminal window
ls -la

Você deve ver os arquivos principais incluindo a implementação da Edge Function, schema SQL e arquivos de configuração.

Passo 2: Configure a conexão Edge SQL

  1. Crie um arquivo .env baseado no exemplo:
Terminal window
cp .env.example .env
  1. Edite o arquivo .env para incluir sua configuração Edge SQL:
Terminal window
# Configuração Edge SQL
EDGE_SQL_CONNECTION_STRING=sua_string_de_conexao_edge_sql
DATABASE_NAME=tasks_db
  1. Obtenha os detalhes de conexão Edge SQL do Console Azion > Edge SQL.

Passo 3: Configure o schema do banco de dados

  1. Conecte-se à sua instância Edge SQL e crie a tabela de tarefas:
CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
completed BOOLEAN DEFAULT FALSE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
  1. Opcionalmente, insira alguns dados de exemplo para teste:
INSERT INTO tasks (title, completed) VALUES
('Completar documentação da API', FALSE),
('Testar deploy da edge function', FALSE),
('Revisar configurações de segurança', TRUE);

Passo 4: Compile o projeto

Compile sua Edge Function para deployment:

Terminal window
pnpm build

Este comando compila sua Edge Function e a prepara para deployment na rede edge da Azion.

Passo 5: Teste localmente

Antes de fazer o deploy, teste sua API localmente:

Terminal window
pnpm dev

Isso inicia um servidor de desenvolvimento local onde você pode testar todos os endpoints da API.

Endpoints da API

A API RESTful de Tarefas fornece os seguintes endpoints:

GET /tasks

Recupera todas as tarefas do banco de dados.

Resposta:

{
"tasks": [
{
"id": 1,
"title": "Completar documentação da API",
"completed": false,
"created_at": "2023-01-01T10:00:00Z",
"updated_at": "2023-01-01T10:00:00Z"
}
]
}

GET /tasks/

Recupera uma tarefa específica por ID.

Resposta:

{
"task": {
"id": 1,
"title": "Completar documentação da API",
"completed": false,
"created_at": "2023-01-01T10:00:00Z",
"updated_at": "2023-01-01T10:00:00Z"
}
}

POST /tasks

Cria uma nova tarefa.

Corpo da requisição:

{
"title": "Título da nova tarefa",
"completed": false
}

Resposta:

{
"task": {
"id": 4,
"title": "Título da nova tarefa",
"completed": false,
"created_at": "2023-01-01T12:00:00Z",
"updated_at": "2023-01-01T12:00:00Z"
}
}

PUT /tasks/

Atualiza uma tarefa existente.

Corpo da requisição:

{
"title": "Título da tarefa atualizada",
"completed": true
}

Resposta:

{
"task": {
"id": 1,
"title": "Título da tarefa atualizada",
"completed": true,
"created_at": "2023-01-01T10:00:00Z",
"updated_at": "2023-01-01T14:00:00Z"
}
}

DELETE /tasks/

Exclui uma tarefa por ID.

Resposta:

{
"message": "Tarefa excluída com sucesso"
}

Deploy na Azion

Passo 1: Autentique-se na Azion

  1. Faça login na sua conta Azion via CLI:
Terminal window
azion login
  1. Siga os prompts de autenticação para conectar sua CLI com sua conta Azion.

Passo 2: Configure a conexão Edge SQL

  1. Crie secrets para sua conexão com o banco de dados:
Terminal window
azion create secret EDGE_SQL_CONNECTION_STRING
  1. Quando solicitado, digite sua string de conexão Edge SQL.

Passo 3: Faça o deploy da Edge Function

Faça o deploy de sua API RESTful na rede edge da Azion:

Terminal window
azion deploy

O processo de deploy irá:

  • Fazer upload do código da sua Edge Function
  • Configurar a edge application
  • Configurar regras de roteamento para todos os endpoints da API
  • Configurar conexões com o banco de dados
  • Fornecer um domínio único

Passo 4: Acesse sua API

Após o deploy, você receberá um domínio como https://xxxxxxx.map.azionedge.net. Sua API RESTful estará disponível nesta URL em alguns minutos após a propagação do DNS.

Entendendo a implementação

Estrutura da Edge Function

A Edge Function da API RESTful inclui:

  1. Configuração do router: Manipulação de diferentes métodos HTTP e rotas
  2. Conexão com banco de dados: Conectando ao Edge SQL
  3. Operações CRUD: Implementação de operações create, read, update, delete
  4. Tratamento de erros: Gerenciamento de erros de banco de dados e requisição
  5. Formatação de resposta: Retorno de respostas JSON consistentes

Exemplo de operações de banco de dados

Veja como as operações de banco de dados são implementadas:

// Obter todas as tarefas
async function getAllTasks() {
const query = 'SELECT * FROM tasks ORDER BY created_at DESC';
const result = await database.query(query);
return result.rows;
}
// Criar uma nova tarefa
async function createTask(title, completed = false) {
const query = `
INSERT INTO tasks (title, completed)
VALUES (?, ?)
RETURNING *
`;
const result = await database.query(query, [title, completed]);
return result.rows[0];
}
// Atualizar uma tarefa
async function updateTask(id, updates) {
const { title, completed } = updates;
const query = `
UPDATE tasks
SET title = ?, completed = ?, updated_at = CURRENT_TIMESTAMP
WHERE id = ?
RETURNING *
`;
const result = await database.query(query, [title, completed, id]);
return result.rows[0];
}

Principais benefícios

  • Performance: Processamento de API na edge reduz latência
  • Escalabilidade: Escala automaticamente com a demanda
  • Distribuição global: Localizações edge fornecem cobertura mundial
  • Consistência de dados: Edge SQL garante conformidade ACID
  • Eficiência de custo: Acesso e transferência de dados otimizados

Testando sua API RESTful

Passo 1: Teste operações CRUD

  1. Criar tarefas: Teste endpoint POST /tasks
  2. Ler tarefas: Teste endpoints GET /tasks e GET /tasks/
  3. Atualizar tarefas: Teste endpoint PUT /tasks/
  4. Excluir tarefas: Teste endpoint DELETE /tasks/

Passo 2: Teste tratamento de erros

  1. Dados inválidos: Teste com corpos de requisição malformados
  2. Recursos inexistentes: Teste com IDs de tarefa inválidos
  3. Erros de banco de dados: Teste tratamento de erros para problemas de conexão
  4. Erros de validação: Teste lógica de validação de entrada

Passo 3: Testes de performance

  1. Tempos de resposta: Meça tempos de resposta da API
  2. Requisições simultâneas: Teste múltiplas requisições simultâneas
  3. Performance do banco de dados: Monitore performance de consultas SQL
  4. Teste de carga: Teste com altos volumes de requisições

Exemplo de uso da API

Usando cURL

Terminal window
# Obter todas as tarefas
curl -X GET https://seu-dominio.map.azionedge.net/tasks
# Criar uma nova tarefa
curl -X POST https://seu-dominio.map.azionedge.net/tasks \
-H "Content-Type: application/json" \
-d '{"title": "Aprender Azion Edge Functions", "completed": false}'
# Atualizar uma tarefa
curl -X PUT https://seu-dominio.map.azionedge.net/tasks/1 \
-H "Content-Type: application/json" \
-d '{"title": "Título da tarefa atualizada", "completed": true}'
# Excluir uma tarefa
curl -X DELETE https://seu-dominio.map.azionedge.net/tasks/1

Usando JavaScript fetch

// Obter todas as tarefas
const tasks = await fetch('/tasks').then(r => r.json());
// Criar uma nova tarefa
const newTask = await fetch('/tasks', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
title: 'Nova tarefa',
completed: false
})
}).then(r => r.json());
// Atualizar uma tarefa
const updatedTask = await fetch('/tasks/1', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
title: 'Tarefa atualizada',
completed: true
})
}).then(r => r.json());

Recursos avançados

Adicionando autenticação

Implemente autenticação para proteger sua API:

async function authenticateRequest(request) {
const authHeader = request.headers.get('Authorization');
if (!authHeader || !authHeader.startsWith('Bearer ')) {
throw new Error('Autenticação necessária');
}
const token = authHeader.substring(7);
return await validateToken(token);
}

Validação de entrada

Adicione validação abrangente de entrada:

function validateTaskData(data) {
const errors = [];
if (!data.title || typeof data.title !== 'string') {
errors.push('Título é obrigatório e deve ser uma string');
}
if (data.title && data.title.length > 255) {
errors.push('Título deve ter menos de 255 caracteres');
}
if (data.completed !== undefined && typeof data.completed !== 'boolean') {
errors.push('Completed deve ser um boolean');
}
return errors;
}

Paginação

Implemente paginação para grandes conjuntos de dados:

async function getTasksPaginated(page = 1, limit = 10) {
const offset = (page - 1) * limit;
const query = `
SELECT * FROM tasks
ORDER BY created_at DESC
LIMIT ? OFFSET ?
`;
const tasks = await database.query(query, [limit, offset]);
const countQuery = 'SELECT COUNT(*) as total FROM tasks';
const totalResult = await database.query(countQuery);
const total = totalResult.rows[0].total;
return {
tasks: tasks.rows,
pagination: {
page,
limit,
total,
totalPages: Math.ceil(total / limit)
}
};
}

Solução de problemas

Problemas comuns e soluções

  • Erros de conexão com banco de dados: Verifique credenciais Edge SQL e string de conexão
  • Endpoint da API não encontrado: Verifique configuração de roteamento e deployment
  • Erros SQL: Valide schema do banco de dados e sintaxe de consulta
  • Problemas de performance: Otimize consultas SQL e indexação do banco de dados

Dicas de debugging

  1. Habilite logging: Adicione logging abrangente para debugging
  2. Teste localmente: Use servidor de desenvolvimento local para isolar problemas
  3. Monitore performance: Rastreie tempos de resposta da API e consultas de banco de dados
  4. Tratamento de erros: Implemente respostas de erro adequadas e códigos de status

Próximos passos

  • Implemente filtragem e ordenação avançadas
  • Adicione atualizações em tempo real com WebSockets
  • Integre com provedores de autenticação
  • Implemente rate limiting e cache da API
  • Adicione documentação abrangente da API com OpenAPI/Swagger