Qué vamos a construir
Un libro de visitas: un formulario en React envía un mensaje a tu servidor, el servidor lo guarda y lo muestra a cada visitante futuro. ¿Recuerdas el formulario del Nivel 2 que no tenía a dónde enviar nada? Hoy saldamos esa deuda.
Te lo muestro: el backend del libro de visitas
En la carpeta my-server, primero instala un paquete más:
npm install cors
Y edita server.js:
const express = require("express");
const cors = require("cors");
const app = express();
app.use(cors()); // allow the frontend on a different port to ask questions
app.use(express.json()); // understand JSON in incoming requests
const messages = [
{ name: "Martin", text: "First message! Long live the guestbook. 📖" },
];
// GET – hand out messages
app.get("/api/messages", (request, response) => {
response.json(messages);
});
// POST – accept a new message
app.post("/api/messages", (request, response) => {
const { name, text } = request.body;
// Never trust input: check it on the server too!
if (!name || !text || name.length > 50 || text.length > 500) {
return response.status(400).json({ error: "Invalid message." });
}
messages.push({ name, text });
response.json({ saved: true });
});
app.listen(3900, () => {
console.log("Server running at http://localhost:3900");
});
Cosas nuevas:
cors()– el frontend corre en el puerto 3901, el servidor en el 3900. Los navegadores suelen bloquear peticiones “cross-origin” así (una regla de seguridad llamada CORS); esto es cómo lo permites en el servidor.app.post(...)– ¡tu primer endpoint POST! Los datos del formulario aparecen enrequest.body.- Comprobar en el servidor – el frontend ya comprueba el formulario, pero un atacante puede saltarse el formulario y enviar una petición directa. Por eso la regla de hierro: el backend siempre comprueba, y nunca confía en el frontend.
status(400)significa “bad request.”
Te lo muestro: el frontend del libro de visitas
En tu proyecto React, crea src/GuestBook.jsx:
import { useState, useEffect } from 'react';
function GuestBook() {
const [messages, setMessages] = useState([]);
const [name, setName] = useState("");
const [text, setText] = useState("");
// On first render: download the messages from the server
useEffect(() => {
fetch("http://localhost:3900/api/messages")
.then((response) => response.json())
.then((data) => setMessages(data));
}, []);
function submit(event) {
event.preventDefault();
fetch("http://localhost:3900/api/messages", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name, text }),
})
.then((response) => response.json())
.then(() => {
setMessages([...messages, { name, text }]); // add it to the screen too
setName("");
setText("");
});
}
return (
<div>
<h2>Guestbook 📖</h2>
{messages.map((message, index) => (
<div className="card" key={index}>
<strong>{message.name}</strong>
<p>{message.text}</p>
</div>
))}
<form onSubmit={submit}>
<input
value={name}
onChange={(event) => setName(event.target.value)}
placeholder="Your name"
/>
<textarea
value={text}
onChange={(event) => setText(event.target.value)}
placeholder="Write a message..."
/>
<button type="submit">Send</button>
</form>
</div>
);
}
export default GuestBook;
Tres cosas nuevas más en React:
useEffect(() => {...}, [])– “ejecuta esto una vez, cuando el componente aparece por primera vez.” El sitio ideal para descargar datos.fetchconmethod: "POST"– enviamos datos;JSON.stringifylos empaqueta en JSON.- Formularios conectados – el campo lee su valor del state (
value={name}) y lo escribe al teclear (onChange). El formulario y el state siempre van sincronizados.
Ahora tú 💪
- Haz funcionar los dos: el servidor en una terminal (
node server.js), React en la otra (npm run dev -- --port 3901). Dos terminales, dos programas – ¡bienvenido al full-stack! - Añade
<GuestBook />a tu app y pruébalo: escribe un mensaje, recarga la página – el mensaje sigue ahí (mientras el servidor siga corriendo). - Adapta el libro de visitas a tu proyecto: 🏫 mensajes para el colegio · 🙋 un tablón de mensajes para amigos · 🌍 consejos de visitantes “¿adónde vamos?” · ⚽ cánticos de los aficionados.
- Prueba a enviar un mensaje vacío – el frontend lo deja pasar (no tiene comprobación), pero el servidor lo rechaza. Luego añade una comprobación al frontend también, para que el formulario sea tan educado como en el Nivel 2.
Los mensajes desaparecen cuando reinicias el servidor – solo viven en un array en memoria. Las aplicaciones de verdad los guardan en una base de datos, que sobrevive a cualquier cosa. Eso es lo primero que aprenderás al terminar este nivel – palabras clave: SQLite, PostgreSQL.
Compruébalo tú: Un mensaje del formulario viaja al servidor, se guarda y vuelve tras recargar la página. Acabas de construir una aplicación full-stack – frontend, backend, API. Esto es exactamente lo que hacen los desarrolladores profesionales cada día.
Lo que te llevas de esta lección
useEffect(..., [])descarga datos en el primer render;fetchcon POST los envía.- La regla de hierro de seguridad: el servidor comprueba cada entrada, aunque el frontend también compruebe.
- Full-stack = dos programas en marcha (3901 + 3900) hablándose por una API.
© 2026 Ing. Martin Polak / AlgoRhino · Condiciones de uso del contenido