Endpoint: Quick Links API (Cloudflare Workers)
Endpoint: Quick Links API (Cloudflare Workers)
API REST implementada como Cloudflare Pages Functions que gestiona los Quick Links del workspace CreaRack — accesos directos a URLs internas y externas categorizados y posicionables.
Archivos fuente
| Archivo | Responsabilidad |
|---|---|
functions/api/quicklinks/index.ts | Colección: GET /api/quicklinks, POST /api/quicklinks |
functions/api/quicklinks/[id].ts | Recurso individual: GET, PUT, DELETE /api/quicklinks/:id |
Esquema de la tabla D1
CREATE TABLE quick_links (
id INTEGER PRIMARY KEY AUTOINCREMENT,
label TEXT NOT NULL, -- máx 80 chars
url TEXT NOT NULL, -- máx 500 chars
description TEXT,
category TEXT DEFAULT 'general', -- ver VALID_CATEGORIES
icon_url TEXT,
position INTEGER DEFAULT 0,
owner_id TEXT,
created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT DEFAULT (datetime('now'))
);
-- Desde migración 0025 (2026-05-14):
CREATE UNIQUE INDEX idx_quick_links_label_url_unique ON quick_links(label, url);
Categorías válidas (VALID_CATEGORIES)
general, monitoring, admin, tools, docs, external (y posiblemente otras definidas en el handler). Cualquier valor no reconocido se normaliza a general.
Endpoints
GET /api/quicklinks
Lista Quick Links. Soporta filtrado opcional por query param category.
Respuesta: 200 OK → array de objetos quick_link.
POST /api/quicklinks
Crea un Quick Link nuevo.
Body JSON:
{
"label": "string (requerido, máx 80)",
"url": "string (requerido, máx 500)",
"description": "string (opcional)",
"category": "string (opcional, default: general)",
"icon_url": "string (opcional)",
"position": "integer (opcional)",
"owner_id": "string (opcional)"
}
Respuestas:
| Status | Condición |
|---|---|
201 Created | Quick Link creado correctamente |
400 Bad Request | label o url ausentes, o superan límite de longitud |
409 Conflict | Ya existe un Quick Link con ese mismo (label, url) |
Implementación post-fix (migración 0025):
INSERT INTO quick_links (label, url, ...)
VALUES (?, ?, ...)
ON CONFLICT(label, url) DO NOTHING
RETURNING *
Si RETURNING * devuelve null (conflict ignorado), el handler responde 409 con { error: 'Ya existe un Quick Link con ese nombre y URL' }.
GET /api/quicklinks/:id
Devuelve un Quick Link por ID.
Respuestas: 200 OK / 404 Not Found.
PUT /api/quicklinks/:id
Actualiza campos de un Quick Link. Acepta cualquier subconjunto de los campos editables (label, url, description, category, icon_url, position). Actualiza updated_at automáticamente.
Respuestas:
| Status | Condición |
|---|---|
200 OK | Actualización correcta |
404 Not Found | ID no existe |
409 Conflict | El nuevo (label, url) colisiona con otro Quick Link existente |
Implementación post-fix: el UPDATE se envuelve en try/catch; si el error incluye 'UNIQUE constraint failed' → 409.
DELETE /api/quicklinks/:id
Elimina un Quick Link por ID.
Respuestas: 200 OK / 404 Not Found.
Logging de actividad
Todos los endpoints de escritura (POST, PUT, DELETE) llaman a logActivity(env, { actor, action, ... }) extrayendo el actor desde la cabecera de request. El actor se resuelve con la función helper actorFrom(request).
Notas de fiabilidad
- UNIQUE INDEX en
(label, url)— introducido en migración0025(2026-05-14) tras el incidente de duplicación por re-aplicación de seeds. Garantiza idempotencia a nivel BD. ON CONFLICT DO NOTHINGen POST — protege contra dobles submit en el modal de la UI y contra re-seeds accidentales.try/catchen PUT — captura violaciones de UNIQUE al editar, evitando errores 500 no controlados.
Véase también
- [[incident—20260514—quicklinks-duplicados-d1-migrations]]
- [[workspace—que-es-workspace]]
- [[workspace—agentes-ia]]