Categorías
Las categorías permiten organizar los posts en grupos temáticos con estructura jerárquica. Una categoría puede contener subcategorías, y estas a su vez más subcategorías. Úsalas para construir menús de navegación del blog, páginas de categoría con sus posts filtrados, o secciones temáticas en tu sitio. La API devuelve el árbol completo en una sola petición.
GET /categories — Árbol de categorías
Devuelve todas las categorías de una web organizadas en árbol. No hay paginación: la respuesta siempre incluye el árbol completo. Esto es intencional — los árboles de categorías suelen ser pequeños (decenas de nodos como máximo) y tenerlos todos de una vez simplifica enormemente la lógica del frontend para construir menús y navegación. Las categorías raíz tienen parent_id: null; sus hijas se anidan en el campo children.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
web_id | string | Sí | ID de la web |
lang | string | No | Código de idioma |
curl "https://tu-panel.com/api/v1/categories?web_id=abc-123&lang=es" \
-H "X-API-Key: tu-api-key" Respuesta esperada 200 OK
{
"data": [
{
"id": "cat-001",
"nombre": "Tecnología",
"slug": "tecnologia",
"description": null,
"parent_id": null,
"children": [
{
"id": "cat-002",
"nombre": "APIs",
"slug": "apis",
"description": "Todo sobre APIs REST y GraphQL",
"parent_id": "cat-001",
"children": []
}
]
},
{
"id": "cat-003",
"nombre": "Diseño",
"slug": "diseno",
"description": null,
"parent_id": null,
"children": []
}
]
} Campos de respuesta
| Campo | Tipo | Descripción |
|---|---|---|
id | UUID | Identificador único |
nombre | string | Nombre de la categoría |
slug | string | URL amigable |
description | string | null | Descripción opcional |
parent_id | UUID | null | ID del padre. null si es categoría raíz |
children | array | Subcategorías hijas (misma estructura, recursiva) |
La estructura de children es recursiva: cada elemento tiene exactamente los mismos campos que la categoría padre, incluyendo su propio children. Para recorrer el árbol completo usa una función recursiva:
// Aplanar el árbol en un array plano de categorías
function flattenCategories(categories, depth = 0) {
return categories.reduce((acc, cat) => {
acc.push({ ...cat, depth, children: undefined })
if (cat.children && cat.children.length > 0) {
acc.push(...flattenCategories(cat.children, depth + 1))
}
return acc
}, [])
}
// Renderizar como menú anidado (ejemplo con HTML)
function renderMenu(categories) {
if (!categories || categories.length === 0) return ''
const items = categories.map(cat => {
const sub = cat.children?.length > 0
? `<ul>${renderMenu(cat.children)}</ul>`
: ''
return `<li><a href="/blog/categoria/${cat.slug}">${cat.nombre}</a>${sub}</li>`
})
return items.join('')
} Casos de uso
Menú de navegación del blog. Llama a este endpoint una vez en el build (o en un componente de servidor) y usa el resultado para renderizar un menú con soporte de desplegables para subcategorías. Con el árbol ya estructurado no necesitas ninguna lógica adicional de agrupación.
Página /categoria/[slug]. Genera una ruta estática por cada categoría usando sus slugs. En la ruta, usa el parámetro category del endpoint de posts para obtener los posts filtrados: /api/v1/posts?web_id=...&category=tecnologia. Combina ambas llamadas para tener el nombre de la categoría y sus posts en la misma página.
Sección "Ver más en [categoría]". Al final de cada post, muestra posts relacionados de la misma categoría. Tienes el slug de la categoría en el campo categories del post — úsalo directamente en el filtro.
Breadcrumbs dinámicos. Con el campo parent_id puedes reconstruir la ruta de migas de pan desde cualquier categoría hasta la raíz recorriendo el árbol hacia arriba.
Consejos y buenas prácticas
- Cachea el árbol de categorías agresivamente — cambia muy poco comparado con los posts. Un TTL de varias horas o invalidación manual cuando se modifica una categoría es suficiente.
- Usa siempre el
slugpara construir las URLs de categoría, nunca elid. El slug está pensado para aparecer en URLs y es legible para el usuario y los buscadores. - Verifica que
childrenexiste y tiene elementos antes de iterar sobre él. Aunque la API siempre devuelve el campo, puede ser un array vacío[]. - Si usas Astro con generación estática, llama a este endpoint dentro de
getStaticPathspara generar todas las páginas de categoría en tiempo de build sin peticiones en runtime.
Errores frecuentes
| Código | Causa probable | Solución |
|---|---|---|
401 | API Key no incluida o incorrecta | Verifica el header X-API-Key y que la clave está activa en el panel |
400 | Falta el parámetro web_id | Incluye web_id en la query string |
200 con data: [] | La web no tiene categorías creadas | Crea al menos una categoría desde el panel antes de llamar al endpoint |