Saltar al contenido.
Blog de Enrique Stolar

Blog


Publicado el 21/07/2026 | Autor: Enrique Stolar

Introducción a APIs y consumo desde una interfaz

Introducción a APIs y consumo desde una interfaz

Serie: Desarrollo de Interfaces

Curso: Desarrollo de Interfaces 1

Capítulo 18: Introducción a APIs y consumo desde una interfaz

Capítulo anterior: CRUD con archivos JSON usando Node.js

Capítulo siguiente: Introducción a bases de datos relacionales y SQL

En los capítulos anteriores construimos una ruta bastante concreta: primero trabajamos con datos en memoria, luego persistimos registros en un archivo JSON usando Node.js. El siguiente paso natural es aprender cómo una interfaz conversa con un servidor. Esa conversación ocurre mediante APIs.

Una API no es una palabra misteriosa reservada para proyectos grandes. En términos prácticos, una API es un conjunto de rutas que permite que una aplicación pida o envíe datos. Cuando una interfaz lista proyectos desde /projects, crea un registro con POST /projects o elimina uno con DELETE /projects/3, está consumiendo una API.

Qué aprenderás hoy

  • Entender qué es una API desde el punto de vista de una interfaz.
  • Diferenciar cliente, servidor, ruta, método HTTP y respuesta.
  • Consumir datos con fetch().
  • Manejar estados de carga, éxito y error.
  • Enviar datos con POST usando JSON.
  • Preparar el camino para un CRUD con MySQL.
Idea clave

La interfaz no debería saber cómo se guardan los datos. Solo necesita saber a qué ruta pedirlos, qué enviar y cómo interpretar la respuesta.

Qué es una API

Una API funciona como un contrato entre dos partes. El frontend pregunta o envía información. El backend responde. Ese contrato define rutas, métodos, datos esperados y posibles respuestas.

Por ejemplo, para un sistema de proyectos podríamos tener estas rutas:

GET    /projects
GET    /projects/1
POST   /projects
PUT    /projects/1
DELETE /projects/1

La ruta indica el recurso. El método HTTP indica la intención. GET lee, POST crea, PUT actualiza y DELETE elimina. Esta convención hace que una aplicación sea más fácil de entender para otras personas y para nuestro propio futuro.

El papel de fetch()

En el navegador, fetch() es la forma moderna de hacer solicitudes HTTP desde JavaScript. Devuelve una promesa, por eso normalmente lo usamos con async y await.

async function loadProjects() {
  const response = await fetch("http://localhost:3000/projects");
  const projects = await response.json();

  console.log(projects);
}

Este ejemplo pide datos al servidor y convierte la respuesta en JSON. Pero todavía le falta algo importante: validar si la respuesta fue correcta.

Validar la respuesta

No todo lo que responde un servidor significa éxito. Puede existir un error 404, un problema 500 o una respuesta sin permisos. Por eso conviene revisar response.ok antes de procesar los datos.

async function requestJSON(url, options = {}) {
  const response = await fetch(url, options);

  if (!response.ok) {
    throw new Error("Error HTTP: " + response.status);
  }

  return response.json();
}

Esta función pequeña nos ayuda a repetir menos código. Si la respuesta está bien, devuelve JSON. Si no, lanza un error que podremos mostrar en la interfaz.

Mostrar datos en la interfaz

Ahora usemos esa función para renderizar proyectos. Partimos de un contenedor HTML:

<section id="project-list" class="cards"></section>
<p id="status-message"></p>

Luego conectamos JavaScript:

const list = document.querySelector("#project-list");
const statusMessage = document.querySelector("#status-message");

function createProjectCard(project) {
  return `
    <article class="project-card">
      <h3>${project.name}</h3>
      <p>Equipo: ${project.team}</p>
      <p>Curso: ${project.course}</p>
      <p>Estado: ${project.status}</p>
    </article>
  `;
}

async function renderProjects() {
  statusMessage.textContent = "Cargando proyectos...";

  try {
    const projects = await requestJSON("http://localhost:3000/projects");

    if (projects.length === 0) {
      list.innerHTML = "<p>No hay proyectos registrados.</p>";
      statusMessage.textContent = "";
      return;
    }

    list.innerHTML = projects.map(createProjectCard).join("");
    statusMessage.textContent = "";
  } catch (error) {
    statusMessage.textContent = "No se pudieron cargar los proyectos.";
  }
}

renderProjects();

Aquí aparece una idea profesional: la interfaz debe comunicar estado. No basta con mostrar datos cuando todo sale bien. También debe informar cuando está cargando y cuando algo falla.

Enviar datos con POST

Para crear un registro desde la interfaz, necesitamos enviar datos al servidor. Usaremos POST, el encabezado Content-Type: application/json y JSON.stringify().

async function createProject(projectData) {
  return requestJSON("http://localhost:3000/projects", {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify(projectData)
  });
}

El navegador envía un texto JSON. El servidor lo recibe, lo convierte en datos y decide cómo guardarlo. En el capítulo anterior lo guardamos en un archivo JSON. En el siguiente capítulo lo guardaremos en MySQL.

Conectar el formulario

Supongamos que tenemos un formulario con campos name, team, course y status. Podemos leerlo con FormData y enviar el objeto al servidor.

const form = document.querySelector("#project-form");

form.addEventListener("submit", async function (event) {
  event.preventDefault();

  const formData = new FormData(form);

  const projectData = {
    name: String(formData.get("name")).trim(),
    team: String(formData.get("team")).trim(),
    course: String(formData.get("course")).trim(),
    status: String(formData.get("status")).trim()
  };

  try {
    await createProject(projectData);
    form.reset();
    await renderProjects();
    statusMessage.textContent = "Proyecto registrado correctamente.";
  } catch (error) {
    statusMessage.textContent = "No se pudo registrar el proyecto.";
  }
});

Observa que después de crear el proyecto volvemos a llamar a renderProjects(). Eso asegura que la interfaz muestre el estado actualizado del servidor.

La interfaz no debe adivinar la base de datos

Esta es una de las ideas más importantes antes de llegar a MySQL. La interfaz no debería estar acoplada al tipo de almacenamiento. Si hoy el backend guarda en JSON y mañana guarda en MySQL, la interfaz debería seguir llamando a rutas parecidas.

Eso nos permite evolucionar el proyecto sin rehacer toda la pantalla. Cambia la capa de persistencia, pero se mantiene el contrato de la API.

Recomendación profesional

Diseña primero el contrato de la API: rutas, métodos, datos de entrada y respuestas. Luego decide si guardarás en JSON, MySQL u otra tecnología.

Estados que toda interfaz debería manejar

Cuando consumimos una API, la interfaz tiene al menos tres estados: cargando, con datos y con error. También puede haber un estado vacío cuando la respuesta fue correcta, pero no hay registros.

  • Cargando: la solicitud está en proceso.
  • Con datos: la respuesta llegó y hay contenido para mostrar.
  • Vacío: la respuesta llegó, pero la lista no tiene registros.
  • Error: hubo un problema de red, servidor o permisos.

Estos estados hacen que una interfaz se sienta más madura. El usuario no debería quedarse mirando una pantalla quieta sin saber qué ocurre.

Errores comunes

  • Usar fetch() sin revisar response.ok.
  • Olvidar Content-Type: application/json al enviar datos.
  • No convertir el objeto con JSON.stringify().
  • Asumir que la API siempre responderá rápido y bien.
  • Mostrar errores solo en consola y no en la interfaz.
  • Acoplar la pantalla a cómo se guardan los datos por dentro.

¿Y CRUD con MySQL?

Sí, CRUD con MySQL viene inmediatamente después. No lo hemos saltado; lo estamos preparando. Primero necesitábamos entender cómo la interfaz consume una API. Ahora que esa comunicación está clara, el siguiente paso será reemplazar el archivo JSON por una base de datos MySQL.

La lógica general se mantendrá: la interfaz hará GET, POST, PUT y DELETE. El servidor seguirá recibiendo solicitudes y devolviendo JSON. Lo que cambiará será la capa de datos: en vez de leer y escribir un archivo, ejecutaremos consultas SQL.

Reto práctico

Reto

Conecta una interfaz HTML con la API de proyectos creada en el capítulo anterior. Debe listar proyectos, mostrar estado de carga, mostrar mensaje cuando no haya datos y permitir registrar un nuevo proyecto usando fetch().

Variante extra: agrega botones para eliminar proyectos desde la interfaz. Después de eliminar, vuelve a cargar la lista desde el servidor.

Conclusión

Consumir una API desde una interfaz es uno de los momentos más importantes en el aprendizaje web. La pantalla deja de ser un documento aislado y se convierte en una aplicación conectada. Ya no inventa sus datos: los solicita, los interpreta y los muestra.

Este capítulo también ordena el camino hacia MySQL. Si sabemos hablar con una API, el tipo de persistencia se vuelve una decisión interna del servidor. Hoy puede ser JSON. Mañana será MySQL. Más adelante podrían ser servicios externos o APIs de terceros.

En el siguiente capítulo construiremos un CRUD con MySQL desde Node.js. Ahí veremos tablas, conexión, consultas preparadas y cómo mantener el mismo contrato de API mientras cambiamos la forma de guardar los datos.

Fuentes consultadas

Compartir este artículo: