Introducción
Un formulario de soporte necesita una API que distinga entre una solicitud válida, un JSON incorrecto, una ruta inexistente y un servicio de tickets no disponible. Usted creará ese límite HTTP con JavaScript, lo probará localmente y después lo implementará junto con un Worker ascendente temporal.
Utilice su propia cuenta de aprendizaje de Cloudflare y los conocimientos sobre autorización del dispositivo adquiridos en el laboratorio de conexión. Este laboratorio comienza en una máquina virtual nueva, con Node.js 22.22.0 y Wrangler 4.131.1 instalado localmente en el proyecto /home/labex/project/support-api. Como requisitos previos, debe conocer las funciones, los objetos y los módulos básicos de JavaScript; aquí se explican el comportamiento de HTTP y las solicitudes asíncronas. Los dos Workers públicos usan únicamente datos sintéticos. El servicio ascendente proporcionado acepta las solicitudes, pero no almacena nada: no es un sistema de tickets persistente. Workers Free y un subdominio workers.dev son suficientes; para este ejercicio pequeño no se necesita una base de datos, un dominio comprado ni una actualización de pago. Las solicitudes cuentan para el uso de Workers de su cuenta.
Eliminará ambos Workers y cerrará la sesión antes de terminar el laboratorio. Mantenga abierto el mismo terminal para conservar las variables del shell utilizadas para los nombres de los recursos y las URL.
Enrutar solicitudes por ruta y método
En este paso, asignará a cada URL compatible un método y una respuesta explícitos. Una ruta identifica la operación; un método describe la acción. GET /health comprueba la disponibilidad y POST /requests aceptará una solicitud de soporte.
Entre en el proyecto preparado y confirme las herramientas:
cd /home/labex/project/support-api
node --version
npx wrangler --version
Espere obtener Node v22.22.0 y Wrangler 4.131.1. La instalación ya está completa; en su propio equipo, instale Node y utilice npm install --save-dev wrangler@4.131.1 dentro de un proyecto. Use npm ci cuando reproduzca un proyecto que incluya su archivo de bloqueo.
Genere un nombre temporal único. openssl rand -hex 6 produce 12 caracteres hexadecimales aleatorios; $(...) inserta esa salida y la asignación del shell la guarda para los comandos posteriores.
WORKER_NAME="labex-support-$(openssl rand -hex 6)"
Escriba la configuración estándar de Wrangler. cat > file <<MARKER escribe las líneas siguientes hasta el marcador de cierre; como el marcador no está entre comillas, el shell sustituye $WORKER_NAME.
cat > wrangler.jsonc <<CONFIG
{
"name": "$WORKER_NAME",
"main": "src/index.js",
"compatibility_date": "2026-09-14",
"workers_dev": true,
"preview_urls": false,
"vars": {"UPSTREAM_URL": "http://127.0.0.1:8081"}
}
CONFIG
main identifica el controlador, compatibility_date selecciona el comportamiento del entorno de ejecución y vars proporciona una dirección ascendente no secreta mediante env. Por ahora, apunta a un accesorio local que iniciará más adelante. Las URL públicas de vista previa están desactivadas para mantener sencillo el inventario de recursos.
Escriba el controlador. El marcador entre comillas JS conserva literalmente el código JavaScript. new URL(...).pathname extrae la ruta. La expresión ternaria selecciona el método permitido; HTTP 405 también anuncia ese método en Allow. Response.json serializa un objeto y establece su tipo de contenido. El controlador async podrá esperar operaciones asíncronas en los pasos posteriores.
cat > src/index.js <<'JS'
export default {
async fetch(request, env) {
const path = new URL(request.url).pathname;
if (path !== '/health' && path !== '/requests') {
return Response.json({error: 'not_found'}, {status: 404});
}
const allowed = path === '/health' ? 'GET' : 'POST';
if (request.method !== allowed) {
return Response.json({error: 'method_not_allowed'}, {
status: 405, headers: {Allow: allowed}
});
}
if (path === '/health') return Response.json({status: 'ok'});
return Response.json({error: 'not_implemented'}, {status: 501});
}
};
JS
Inicie Wrangler localmente en segundo plano: > redirige la salida, 2>&1 incluye los errores y & devuelve el prompt del terminal mientras el servidor sigue ejecutándose.
npx wrangler dev --port 8080 > api.log 2>&1 &
cat api.log
Espere hasta que el registro indique que el servidor está listo en el puerto 8080. Vuelva a ejecutar cat api.log si todavía está iniciándose. curl -i incluye el estado y las cabeceras HTTP:
curl -i http://127.0.0.1:8080/health
curl -i http://127.0.0.1:8080/missing
curl -i http://127.0.0.1:8080/requests
Espere, respectivamente, un estado 200 con {"status":"ok"}, un estado 404 con {"error":"not_found"} y un estado 405 con {"error":"method_not_allowed"} junto con Allow: POST. Estas respuestas de error son intencionadas. Use el botón de verificación mientras el servidor siga ejecutándose.
Analizar y validar la entrada JSON
En este paso, rechazará las entradas con formato incorrecto antes de llamar a cualquier servicio ascendente. HTTP 415 significa que el tipo de medio no es compatible, 400 significa que no se puede analizar el JSON y 422 significa que los datos analizados no cumplen el contrato. subject debe ser una cadena que contenga entre 1 y 80 caracteres después de eliminar los espacios en blanco.
Reemplace el controlador por esta versión completa. headers.get lee el tipo de medio declarado; dividir en ; permite un parámetro de codificación de caracteres. await request.json() espera el análisis y consume el cuerpo una sola vez. Un bloque try/catch convierte una excepción de análisis en una respuesta predecible. JSON también puede representar null, matrices o números, por lo que la validación comprueba la estructura antes de usar métodos de cadenas. trim() normaliza el subject aceptado.
cat > src/index.js <<'JS'
export default {
async fetch(request, env) {
const path = new URL(request.url).pathname;
if (path !== '/health' && path !== '/requests') {
return Response.json({error: 'not_found'}, {status: 404});
}
const allowed = path === '/health' ? 'GET' : 'POST';
if (request.method !== allowed) {
return Response.json({error: 'method_not_allowed'}, {
status: 405, headers: {Allow: allowed}
});
}
if (path === '/health') return Response.json({status: 'ok'});
const mediaType = (request.headers.get('content-type') || '').split(';')[0].trim().toLowerCase();
if (mediaType !== 'application/json') {
return Response.json({error: 'unsupported_media_type'}, {status: 415});
}
let body;
try {
body = await request.json();
} catch {
return Response.json({error: 'invalid_json'}, {status: 400});
}
if (!body || Array.isArray(body) || typeof body.subject !== 'string' ||
body.subject.trim().length < 1 || body.subject.trim().length > 80) {
return Response.json({error: 'invalid_subject'}, {status: 422});
}
const subject = body.subject.trim();
return Response.json({subject}, {status: 201});
}
};
JS
Wrangler se recarga cuando cambia el código fuente. Compruebe cat api.log para detectar errores de compilación. Envíe una solicitud válida: -H proporciona una cabecera y --data proporciona el cuerpo y selecciona POST. Las comillas simples conservan las comillas dobles del JSON en el shell.
curl -i http://127.0.0.1:8080/requests -H "Content-Type: application/json" --data '{"subject":" Printer offline "}'
Espere un estado 201 y {"subject":"Printer offline"}. Esto es una confirmación en memoria, no un ticket guardado. Pruebe tres rutas de rechazo diferentes:
curl -i http://127.0.0.1:8080/requests -H "Content-Type: application/json" --data '{'
curl -i http://127.0.0.1:8080/requests -H "Content-Type: application/json" --data '{"subject":" "}'
curl -i http://127.0.0.1:8080/requests -H "Content-Type: text/plain" --data 'hello'
Espere 400 invalid_json, 422 invalid_subject y 415 unsupported_media_type. Pruebe también null, [] y {"subject":5} como JSON; cada uno debe devolver 422 en lugar de producir una excepción. Use el botón de verificación; comprobará estos límites y conservará el comportamiento de disponibilidad y enrutamiento.
Llamar a un servicio ascendente y contener sus errores
En este paso, conectará la API a un simulador de servicio de tickets proporcionado. Un servicio ascendente es una dependencia a la que llama su servicio. El simulador devuelve un ticket sintético para los subject normales y HTTP 503 para el subject especial simulate-outage; nunca almacena las solicitudes.
Inspeccione el código fuente proporcionado para entender el accesorio y, después, configure su propia identidad única de Worker:
cat upstream/index.js
cat > upstream/wrangler.jsonc <<CONFIG
{
"name": "${WORKER_NAME}-upstream",
"main": "index.js",
"compatibility_date": "2026-09-14",
"workers_dev": true,
"preview_urls": false
}
CONFIG
--config selecciona esta segunda configuración. Use el puerto 8081 y un puerto de inspector independiente para que ambos Workers locales puedan ejecutarse al mismo tiempo:
npx wrangler dev --config upstream/wrangler.jsonc --port 8081 --inspector-port 9230 > upstream.log 2>&1 &
cat upstream.log
curl -i http://127.0.0.1:8081/health
Espere a que esté listo y espere un estado 200 con {"service":"support-upstream","status":"ok"}. Ahora reemplace el controlador principal por la integración completa. La función global fetch realiza una solicitud saliente; JSON.stringify codifica el subject validado. await espera la respuesta. Los errores HTTP no producen excepciones, por lo que upstream.ok comprueba explícitamente el estado; catch gestiona por separado una conexión fallida o una respuesta JSON que no se puede leer. HTTP 502 informa al cliente de que la dependencia falló sin exponer el cuerpo de respuesta interno.
cat > src/index.js <<'JS'
export default {
async fetch(request, env) {
const path = new URL(request.url).pathname;
if (path !== '/health' && path !== '/requests') {
return Response.json({error: 'not_found'}, {status: 404});
}
const allowed = path === '/health' ? 'GET' : 'POST';
if (request.method !== allowed) {
return Response.json({error: 'method_not_allowed'}, {
status: 405, headers: {Allow: allowed}
});
}
if (path === '/health') return Response.json({status: 'ok'});
const mediaType = (request.headers.get('content-type') || '').split(';')[0].trim().toLowerCase();
if (mediaType !== 'application/json') {
return Response.json({error: 'unsupported_media_type'}, {status: 415});
}
let body;
try {
body = await request.json();
} catch {
return Response.json({error: 'invalid_json'}, {status: 400});
}
if (!body || Array.isArray(body) || typeof body.subject !== 'string' ||
body.subject.trim().length < 1 || body.subject.trim().length > 80) {
return Response.json({error: 'invalid_subject'}, {status: 422});
}
const subject = body.subject.trim();
try {
const upstream = await fetch(`${env.UPSTREAM_URL}/tickets`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({subject})
});
if (!upstream.ok) {
return Response.json({error: 'upstream_unavailable'}, {status: 502});
}
const ticket = await upstream.json();
return Response.json({ticket: ticket.ticket, subject}, {status: 201});
} catch {
return Response.json({error: 'upstream_unavailable'}, {status: 502});
}
}
};
JS
curl -i http://127.0.0.1:8080/requests -H "Content-Type: application/json" --data '{"subject":"Printer offline"}'
curl -i http://127.0.0.1:8080/requests -H "Content-Type: application/json" --data '{"subject":"simulate-outage"}'
Espere un estado 201 con {"ticket":"demo-1001","subject":"Printer offline"} y, después, un estado 502 con {"error":"upstream_unavailable"}. El diagnóstico interno del simulador no debe aparecer. El subject es sintético y este endpoint no produce efectos persistentes. Use el botón de verificación con ambos servidores locales en ejecución.
Este laboratorio utiliza HTTP normal para practicar el límite con un servicio externo. Un laboratorio posterior enseña los enlaces de servicio para las llamadas internas entre Workers. Los tiempos de espera limitados y los diagnósticos más detallados se enseñan en Diagnosticar fallos de Workers. El accesorio devuelve respuestas pequeñas y limitadas; una API de producción también debe limitar el tamaño de las solicitudes y respuestas no confiables.
Implementar y probar la API pública
En este paso, implementará ambos Workers en la misma cuenta de aprendizaje y reemplazará la dirección ascendente local por su URL pública. Detenga primero ambos procesos locales. Inspeccione jobs y use el número real de cada proceso; los ejemplos suponen que la API es 1 y el servicio ascendente es 2.
jobs
kill %1 %2
Autorice esta máquina virtual nueva. La concesión identifica su cuenta y permite implementar y eliminar Workers. El permiso final coincide con la concesión de la lección de implementación, aunque este laboratorio no necesita una transmisión de registros.
npx wrangler login --device --browser=false --scopes account:read user:read workers_scripts:write workers_tail:read
Abra el enlace del navegador que se muestra, introduzca el código actual del dispositivo, revise los permisos de Wrangler —incluido el acceso en segundo plano obligatorio—, seleccione únicamente su cuenta de aprendizaje y autorice. Vuelva al terminal y espere a que termine.
npx wrangler whoami --json
Confirme loggedIn: true, el nombre de la cuenta y su ID real en accounts. Sustituya YOUR_ACCOUNT_ID más abajo por ese ID. Conserve los nombres generados en el paso 1; si perdió una variable, lea la configuración guardada y restáurela en lugar de generar otro nombre de recurso.
cat > upstream/wrangler.jsonc <<CONFIG
{
"name": "${WORKER_NAME}-upstream",
"main": "index.js",
"compatibility_date": "2026-09-14",
"workers_dev": true,
"preview_urls": false,
"account_id": "YOUR_ACCOUNT_ID"
}
CONFIG
npx wrangler deploy --config upstream/wrangler.jsonc
Copie la URL exacta de workers.dev que aparece en la salida de la implementación. Reutilice el subdominio existente de la cuenta. Si Wrangler ofrece registrar un subdominio por primera vez, elija un nombre disponible y siga la confirmación; no cambie un subdominio existente de la cuenta.
Ahora vuelva a escribir la configuración principal y sustituya ambos marcadores de posición por el ID de su cuenta y la URL del servicio ascendente, sin una barra final. global_fetch_strictly_public hace que las solicitudes salientes de fetch() utilicen el enrutamiento público de Internet, incluido el otro Worker en el subdominio workers.dev de esta cuenta. Sin esta opción, esta llamada HTTP dentro de la misma zona puede fallar aunque ambos Workers funcionen de manera independiente. Esta opción pertenece a la configuración de la API implementada; el accesorio local de bucle invertido anterior no la necesita. Consulte la guía de Fetch API.
cat > wrangler.jsonc <<CONFIG
{
"name": "$WORKER_NAME",
"main": "src/index.js",
"compatibility_date": "2026-09-14",
"compatibility_flags": ["global_fetch_strictly_public"],
"workers_dev": true,
"preview_urls": false,
"account_id": "YOUR_ACCOUNT_ID",
"vars": {"UPSTREAM_URL": "YOUR_UPSTREAM_URL"}
}
CONFIG
cat wrangler.jsonc
npx wrangler deploy
Copie la URL de la API principal de la salida de la implementación en la variable siguiente:
API_URL="https://YOUR_API.YOUR_SUBDOMAIN.workers.dev"
curl -i "$API_URL/health"
curl -i "$API_URL/requests" -H "Content-Type: application/json" --data '{"subject":"Printer offline"}'
curl -i "$API_URL/requests" -H "Content-Type: application/json" --data '{"subject":"simulate-outage"}'
curl -i "$API_URL/requests" -H "Content-Type: application/json" --data '{'
Espere los mismos contratos que en el entorno local: estado 200 para la comprobación de disponibilidad, estado 201 para el ticket sintético, estado 502 para el error ascendente y estado 400 para el JSON incorrecto. Espere a que se propague el nombre de host antes de volver a intentar si aparecen errores de conectividad. En el Dashboard, seleccione la misma cuenta de aprendizaje y abra Compute → Workers & Pages. Busque ambos nombres exactos y compare sus direcciones con la salida de la implementación. Este es un punto de comprobación de solo lectura; no cree aplicaciones duplicadas allí.
El ejemplo siguiente muestra la API principal y su servicio -upstream correspondiente. En la barra lateral izquierda, expanda Compute y seleccione Workers & Pages. Use Search applications si su cuenta contiene otros proyectos. Compare los nombres completos generados y las direcciones que aparecen debajo con las dos salidas de implementación; su sufijo aleatorio y el subdominio de la cuenta serán diferentes de los de este ejemplo.

Ambos recursos deben aparecer en la misma cuenta seleccionada. Su presencia confirma dónde se implementaron; las respuestas HTTP anteriores determinan si la API funciona. Si falta alguno de los nombres, compruebe el selector de cuenta y la salida de la implementación antes de volver a intentarlo. No use Create application para duplicar una implementación realizada mediante la CLI.
Use el botón de verificación. Comprobará de forma independiente la propiedad de ambos Workers, el enlace ascendente implementado y las respuestas públicas positivas y negativas. Solo enviará solicitudes sintéticas sin estado al simulador de este laboratorio.
Eliminar ambos Workers temporales
En este paso, eliminará la API y su servicio ascendente mientras la autorización siga disponible para poder verificar el resultado. Estos son los únicos recursos de la nube creados por este laboratorio. Inspeccione ambas configuraciones antes de eliminarlas:
cat wrangler.jsonc
cat upstream/wrangler.jsonc
Confirme el nombre principal labex-support-... y el sufijo coincidente -upstream, con el mismo ID de la cuenta de aprendizaje. Elimine primero la API principal y después el servicio ascendente. En cada confirmación, compruebe el nombre exacto y pulse la única tecla y.
npx wrangler delete
npx wrangler delete --config upstream/wrangler.jsonc
Wrangler 4.131.1 puede eliminar un Worker y después mostrar un error de autenticación al comprobar los datos de KV de Workers Sites antiguos, porque esta concesión no tiene acceso a KV. Ese diagnóstico concreto no demuestra que la eliminación haya tenido éxito o haya fallado. No conceda permisos adicionales solo para ocultarlo. Actualice Workers & Pages y use el botón de verificación: un inventario autorizado correcto debe confirmar que faltan ambos nombres. Los errores de red o de autorización no son concluyentes; resuélvalos antes de continuar. Conserve las demás aplicaciones, su cuenta de aprendizaje y su subdominio.
Desconectar la máquina virtual
En este paso, eliminará la autorización de Wrangler de esta máquina virtual después de que se supere la comprobación de limpieza de los dos recursos. Cerrar la sesión no elimina los Workers; por eso la limpieza se realiza primero.
npx wrangler logout
npx wrangler whoami --json
Espere obtener explícitamente "loggedIn": false. Un comando de estado sin autenticación puede terminar con un código distinto de cero; esto es normal cuando su resultado estructurado informa claramente de que se cerró la sesión. Un error de red no equivale a esto. Use el botón de verificación y, después, finalice el entorno de LabEx. El inicio de sesión del navegador y la cuenta de aprendizaje seguirán disponibles para laboratorios posteriores; cada máquina virtual nueva solicitará su propia autorización.
Resumen
Creó una API HTTP consciente del método, analizó y validó JSON, normalizó los datos aceptados y convirtió un fallo del servicio ascendente en un error público predecible. Probó solicitudes normales y rechazadas localmente y en Cloudflare, comprobó la propiedad de ambas implementaciones, eliminó los recursos temporales y desconectó la máquina virtual.
Como referencia, consulte las API oficiales Request API, Response API y Fetch API.

