WU / DOCSUNIVERSAL MICROFRONTENDS
ES

Un servicio conectado con WU

Publica un contrato, autoriza a un cliente y recorre solicitudes RPC con versiones, validación, cancelación y limpieza.

Del cliente a una respuesta

Si es tu primera integración RPC, empieza por Una suma entre aplicaciones. Esa receta incluye todos los archivos para tu workspace. Este capítulo amplía el patrón con descubrimiento de contratos, cancelación y el servicio ejecutable del laboratorio.

En Servicios y RPC, dos aplicaciones WU colaboran con permisos diferentes. El proveedor publica qué servicio ofrece y atiende un canal; el cliente consume ese contrato y solicita una respuesta. El recorrido permite probar datos válidos, errores, incompatibilidad de versiones, cancelación y retirada del proveedor.

Cliente WU
  → consume('docs:backend:service', '^1.0.0')
  → request('docs:backend:request', solicitud)
  → handler del proveedor WU
  → respuesta { status, headers, body, execution }

Las solicitudes viajan por el RPC de WU dentro del runtime. status, headers y body son miembros del contrato de respuesta; no significan que el portal haya abierto una conexión HTTP o un puerto de servidor.

Solicitar y conceder la autoridad necesaria

Cada manifest declara las capacidades que su app solicita. El proveedor necesita rpc.provide:docs:backend:*; el cliente, rpc.call:docs:backend:*. El shell concede esos scopes al inicializar ambas aplicaciones:

await wu.init({
  sandbox: 'module',
  apps: [
    {
      name: 'backend-service',
      url: '/microfrontends/backend-service',
      grants: ['rpc.provide:docs:backend:*'],
    },
    {
      name: 'backend-client',
      url: '/microfrontends/backend-client',
      grants: ['rpc.call:docs:backend:*'],
    },
  ],
});

Las requests del manifest y los grants del shell deben coincidir. El permiso efectivo procede de su intersección. El código de la app utiliza context.wu, la facade scoped recibida en mount; no necesita capturar el singleton privilegiado del host. La referencia de permisos desarrolla los scopes y su revocación.

Publicar el canal y el contrato

Dentro del montaje del proveedor, appWu es esa facade scoped y handleRequest implementa el servicio:

const release = appWu.handle(
  'docs:backend:request',
  handleRequest,
  { version: '1.0.0', allow: ['backend-client'] },
);

const contract = appWu.provide(
  'docs:backend:service',
  { channel: 'docs:backend:request', method: 'POST' },
  {
    version: '1.0.0',
    shape: { channel: 'string', method: 'string' },
  },
);

handle registra quién responde al canal. provide publica los datos que necesita el consumidor para descubrirlo. La allowlist del handler limita los solicitantes a backend-client; disponer de un grant no elimina esa comprobación adicional. shape comprueba miembros del contrato y sus tipos, mientras que la validación del cuerpo pertenece al servicio.

En WU Framework 4.0.0, wu.handle(channel, handler, options) y wu.eventBus.handle(channel, handler, options) conservan versión y allowlist. Dentro de una microapp usa context.wu.handle: además de esas opciones, aplica la identidad y los grants de la app. Consulta la página de versiones para identificar el runtime del laboratorio.

El nombre publicado con provide pertenece al primer proveedor. Otra app, o el host al intentar sustituirla, recibe WU_CAPABILITY_OWNED hasta que el propietario ejecute revoke o se desmonte con unmount. La versión del contrato no permite saltarse esa propiedad.

Consumir y llamar desde el cliente

El cliente obtiene un proxy del contrato y solicita un rango compatible. Acceder a api.channel resuelve el proveedor disponible y comprueba ese rango:

const api = appWu.consume('docs:backend:service', '^1.0.0');
const channel = api.channel;
const controller = new AbortController();

const pending = appWu.request(channel, {
  method: api.method,
  path: '/validate',
  body: JSON.stringify({ name: 'catalog', entry: 'entry.js' }),
}, {
  version: '^1.0.0',
  timeout: 3500,
  signal: controller.signal,
});

const response = await pending;
console.log(response.status, response.body);

Hay dos comprobaciones de compatibilidad: la del contrato consumido y la del handler RPC. El escenario de versión incompatible solicita ^2.0.0 al contrato 1.0.0; falla al resolverlo, antes de iniciar trabajo en el servicio. Un proveedor retirado tampoco puede atender una solicitud nueva. Revisa eventos, RPC y contratos para sus firmas y errores.

Diferenciar una respuesta de un rechazo

El servicio espera POST, una ruta conocida y un cuerpo string de hasta 4096 bytes UTF-8.

Solicitud Respuesta del servicio
/validate con JSON válido y name/entry presentes 200 con ok: true
/validate con un manifest que no cumple esas reglas 422 con errores de validación
/uppercase 200 con el texto ASCII convertido a mayúsculas
/failure 500 para el fallo controlado del servicio
/slow sin cancelar 504 al vencer el límite de trabajo de 2500 ms
Ruta desconocida 404 sin iniciar el trabajo
Método distinto de POST 405
Estructura de solicitud inválida 400
Cuerpo que excede el límite 413

Estas respuestas resuelven la promesa RPC con un objeto: el cliente debe comprobar response.status. La incompatibilidad de contrato, la ausencia del proveedor o la cancelación se manejan como rechazos, mediante try/catch.

La receta de manifest valida únicamente name y entry. Su resultado declara scope: "name+entry" y completeValidation: false; no comprueba el manifest entero, permisos, rutas publicadas ni existencia del entry. Consulta configuración y manifests y WU doctor para continuar el diagnóstico de un proyecto.

Cancelar y desmontar sin conservar trabajo activo

Mientras la solicitud siga pendiente, el cliente puede ejecutar:

controller.abort();

El handler recibe el contexto RPC, que incluye signal. En este ejemplo, el proveedor conecta esa señal con la interrupción de su ejecutor. Un handler que ignore signal puede seguir trabajando aunque el cliente haya dejado de esperar.

El plazo RPC de 3500 ms y el límite de trabajo de 2500 ms tienen efectos diferentes: el primero limita la espera de WU; el segundo permite al servicio terminar el trabajo y responder 504. La interfaz incluye una receta lenta para observar cancelación antes de ambos plazos.

Al desmontar el proveedor, la implementación detiene sus solicitudes activas y retira lo que publicó:

backend.dispose();
release();
contract.revoke();

WU también revoca la autoridad asociada con la app. Al montar de nuevo se registran un handler y un contrato nuevos. Cada petición libera su listener de abort, temporizador y ejecutor al finalizar, fallar o cancelar. La guía de lifecycle explica cómo vincular esa propiedad de recursos con mount y unmount.

Leer y comprobar el ejemplo

El código del proveedor muestra el manejo de solicitudes y su limpieza. Para ejecutar las comprobaciones desde el repositorio del portal:

npm ci
npm run build
npm run dev:shell
# En otra terminal:
npm run test:backend

La prueba recorre respuestas, versión incompatible, revocación, remontaje, timeout, cancelación y desmontaje durante una solicitud. También verifica que la ejecución no conserve Workers al terminar y que el recorrido no produzca errores de página.

Implementación del ejemplo

El proveedor utiliza un programa WASI compilado e incluido en el proyecto, ejecutado en un Worker. Esto permite procesar datos reales y detener el trabajo desde el navegador. El host y los archivos virtuales pertenecen a la implementación del servicio; el contrato público estudiado aquí es WU. El framework no incorpora un motor WASI general.

Puedes sustituir esa implementación por un servicio autorizado de tu aplicación conservando un contrato compatible y probando sus respuestas, errores y limpieza. Un servicio remoto debe volver a validar identidad, permisos y datos. Para renderizar páginas en Node o conectar un cliente MCP externo siguen siendo necesarios sus procesos y transportes: consulta SSR e IA/MCP.

WU SE CONSTRUYE CONTIGO

¿Encontraste un bug? ¿Tienes una idea?

Tu experiencia mejora WU. Cuéntanos qué falla o ayuda a sostener su desarrollo.