Wat we bouwen
Een gastenboek: een formulier in React stuurt een bericht naar je server, de server slaat het op en toont het aan elke toekomstige bezoeker. Herinner je het formulier uit Level 2 dat nergens naartoe kon? Vandaag lossen we die schuld in.
Ik laat je zien: de gastenboek-backend
In de map my-server eerst nog een package installeren:
npm install cors
En bewerk 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");
});
Nieuw:
cors()– de frontend draait op poort 3901, de server op 3900. Browsers blokkeren normaal zulke “cross-origin”-verzoeken (een veiligheidsregel CORS); zo sta je het toe op de server.app.post(...)– je eerste POST-endpoint! Formulierdata staat inrequest.body.- Controleren op de server – de frontend controleert al, maar een aanvaller kan het formulier omzeilen. Daarom geldt de ijzeren regel: de backend controleert altijd en vertrouwt de frontend nooit.
status(400)betekent “slecht verzoek.”
Ik laat je zien: de gastenboek-frontend
In je React-project maak je 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;
Drie laatste nieuwe dingen in React:
useEffect(() => {...}, [])– “voer dit één keer uit als de component voor het eerst verschijnt.” De ideale plek om data te downloaden.fetchmetmethod: "POST"– we sturen data;JSON.stringifypakt het in JSON.- Gekoppelde formulieren – het veld leest zijn waarde uit state (
value={name}) en schrijft terug tijdens typen (onChange). Formulier en state blijven synchroon.
Nu jij 💪
- Laat beide draaien: de server in één terminal (
node server.js), React in de andere (npm run dev -- --port 3901). Twee terminals, twee programma’s – welkom bij full-stack! - Voeg
<GuestBook />toe aan je app en probeer: schrijf een bericht, ververs de pagina – het bericht is er nog (zolang de server draait). - Pas het gastenboek aan je project aan: 🏫 berichten voor de school · 🙋 een prikbord voor vrienden · 🌍 “waar moeten we naartoe?”-tips van bezoekers · ⚽ leuzen van fans.
- Probeer een leeg bericht te sturen – de frontend laat het door (geen check), maar de server wijst af. Voeg dan ook een check aan de frontend toe, zoals in Level 2.
Berichten verdwijnen als de server herstart – ze leven alleen in een array in het geheugen. Echte applicaties slaan ze op in een database, die alles overleeft. Dat is het eerste om te leren na dit level – trefwoorden: SQLite, PostgreSQL.
Controleer jezelf: Een bericht van het formulier gaat naar de server, wordt opgeslagen en komt terug na het verversen. Je bouwde net een full-stack applicatie – frontend, backend, API. Zo werken professionele ontwikkelaars elke dag.
Wat neem je mee uit deze les
useEffect(..., [])downloadt data bij eerste render;fetchmet POST stuurt het.- De ijzeren veiligheidsregel: de server controleert elke invoer, ook als de frontend controleert.
- Full-stack = twee draaiende programma’s (3901 + 3900) die via een API praten.
© 2026 Ing. Martin Polak / AlgoRhino · Contentgebruiksvoorwaarden