Frontend: datos, APIs y APIs de Backstage

Objetivos del capítulo
  • Usar useApi y fetchApi con tipos TypeScript.

  • Consumir el catalog desde tu plugin.

  • Manejar errores con ErrorApi, notificaciones e identidad.

ApisRegistry: el bus del frontend

El backend tiene coreServices; el frontend tiene ApisRegistry. Es el mismo concepto: una pieza pide lo que necesita y el shell se lo inyecta. La sala del restaurante tiene su propio sistema de pedidos: cada camarero pide al jefe de sala y el jefe le pasa lo que necesita.

Backstage expone APIs de sistema a través de refs:

  • :code:`catalogApiRef` — acceso al catalog.

  • :code:`errorApiRef` — notificación de errores.

  • :code:`identityApiRef` — usuario autenticado.

  • :code:`notificationApiRef` — toasts.

  • :code:`fetchApiRef` — fetch configurado con auth headers.

Diagram
Figure 12. ApisRegistry como bus de servicios

Consumir el catalog con useApi

Un hook que consulta el catalog de Sazón Foods:

import { useEffect, useState } from 'react';
import { useApi, errorApiRef } from '@backstage/core-plugin-api';
import { catalogApiRef } from '@backstage/plugin-catalog-react';
import { Entity } from '@backstage/catalog-model';

export function useSazonComponents(): {
  components: Entity[] | null;
  loading: boolean;
} {
  const catalogApi = useApi(catalogApiRef);
  const errorApi = useApi(errorApiRef);
  const [components, setComponents] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    catalogApi
      .getEntities({ filter: { kind: 'Component', 'spec.system': 'sazon-restaurant' } })
      .then(res => setComponents(res.items))
      .catch(err => errorApi.post(err))
      .finally(() => setLoading(false));
  }, [catalogApi, errorApi]);

  return { components, loading };
}
Lo que acabas de hacer
  • :code:`useApi(catalogApiRef)` resuelve el API por ref.

  • :code:`getEntities({ filter })` consulta entidades con un filtro estructurado.

  • :code:`errorApi.post(err)` muestra el error en la UI estándar (no console.error).

Filtros de catalog

El parámetro filter es por kind, namespace, spec, etc. Ejemplos:

  • :code:`{ kind: 'Component' }` — todos los componentes.

  • :code:`{ kind: 'Component', 'spec.system': 'sazon-restaurant' }` — los del System.

  • :code:`{ kind: 'API', 'spec.type': 'openapi' }` — APIs declaradas.

Combina con :code:`fields:` para reducir el payload.

Consumir tu propio backend

Para llamar a un endpoint custom (como /api/sazon/status del :cap-06), usa fetchApiRef o el fetch global según el caso:

export function useCustomSazonStatus(): { rows: { service: string; status: string }[] | null } {
  const [rows, setRows] = useState<{ service: string; status: string }[] | null>(null);
  useEffect(() => {
    // /api/sazon-status is proxied to the backend (see app-config dev server).
    fetch('/api/sazon/status')
      .then(r => r.json())
      .then(j => setRows(j.rows ?? []))
      .catch(() => setRows([]));
  }, []);
  return { rows };
}
Proxy en desarrollo

:code:`fetch('/api/…​')` desde el navegador solo funciona si el frontend tiene un proxy al backend en app-config.yaml:

proxy:
  '/api/sazon': http://localhost:7007/api/sazon

En producción, el frontend se sirve detrás del mismo dominio que el backend o un proxy inverso.

Manejo de errores

Tres reglas:

  1. Nunca console.error y ya. Usa errorApi.post(err) para que aparezca la UI de error.

  2. Loading y error states son obligatorios en cualquier fetch. Muestra un <Progress /> mientras loading y un <EmptyState /> si la lista está vacía.

  3. 401/403 se manejan vía el ErrorApi. Backstage los trata especialmente: el 401 te redirige a login.

Example 9. Receta del capítulo
  1. Importa los refs (catalogApiRef, errorApiRef) que necesites.

  2. Usa useApi(ref) para resolverlos en componentes.

  3. Para datos de catálogo, prefiere catalogApi.getEntities() sobre fetch manual.

  4. Para endpoints custom, configura el proxy y usa fetchApiRef.

  5. Maneja loading, error y empty state en cada componente que hace fetch.

Resumen

  • ApisRegistry expone servicios del shell a los plugins.

  • useApi(ref) los resuelve en componentes.

  • catalogApiRef da acceso al catalog con filtros estructurados.

  • errorApi.post(err) muestra errores en la UI estándar.

Glosario del capítulo

ApisRegistry

Bus de APIs del shell, equivalente frontend de coreServices.

ref

Objeto ApiRef<T> que identifica un API por su tipo T.

useApi

Hook que resuelve un ref en su implementación inyectada.

fetchApiRef

Ref al fetch configurado con auth headers del shell.

proxy

Config de app-config.yaml que redirige paths del dev server al backend.

Próximo capítulo

Componentes, tablas y UX consistente —composición con Material UI y los componentes de @backstage/core-components.