Vezérlőpult
3. Express bevezetés · Express alapok

Express alapok · 3. tananyag

Express bevezetés

Az előző fejezet végén összegyűlt egy lista arról, mi mindent kellene még megírnunk kézzel. Pontosan ezt kapjuk meg az Expressben. Most feltelepítjük, megírjuk vele az első alkalmazást, és megnézzük, mit vesz le a vállunkról — meg azt is, mit nem.

2 tanóraExpress 5.2Az első keretrendszer

A fejezet végén tudni fogod

1Mi az Express?

Az Express a Node.js legelterjedtebb webes keretrendszere. Nem cseréli le a beépített http modult — ráépül: ugyanaz a szerver fut alatta, csak kényelmesebb felülettel.

Egy mondatban: az Express a kérés-válasz kezelés kényelmi rétege.

A TE KÓDOD app.get("/api/products", (req, res) => …) EXPRESS útvonalválasztás · middleware · res.json() · req.body NODE — http MODUL kapcsolatkezelés · a HTTP-üzenet ki- és becsomagolása HÁLÓZAT (TCP) a bájtok tényleges szállítása A KÉRÉS FELFELÉ HALAD A VÁLASZ LEFELÉ AMIT EBBŐL ÉRTS MEG Az Express nem „másik szerver”. A Node szervere fut alatta — az Express csak azt kényelmesebbé teszi. Ezért ismerős a req és a res az előző fejezetből.
1. ábra — Rétegek. Az Express a Node http moduljára épül, nem helyette van.

Mit ad?

Amit adMit jelent a gyakorlatban?
Útvonalkezelésapp.get("/api/products/:id", …) — nincs több if-lánc és split("/")
Middleware-láncKözös lépések (naplózás, hitelesítés) egy helyen, minden végpontra
Válasz-segédfüggvényekres.json(), res.status(), res.send() — a Content-Type automatikus
Törzs-feldolgozásexpress.json() — és már van req.body
Statikus fájlokexpress.static("public") — egy sor
HibakezelésKözponti hibakezelő, az 5-ösben az aszinkron hibákkal együtt
ÖkoszisztémaTöbb ezer kész middleware: CORS, tömörítés, biztonsági fejlécek, feltöltés

Mit NEM ad?

Ezt legalább ilyen fontos tudni — az Express szándékosan minimalista:

Amit NEM adMit kell magadnak megoldanod?
Adatbázis-kezelésKülön eszköz kell (nálunk: Prisma, a 3. blokkban)
ValidációKülön könyvtár (nálunk: Zod) vagy kézzel
ProjektszerkezetNincs előírt mappastruktúra — te alakítod ki
HitelesítésKülön csomagok (JWT, jelszó-hashelés)
Sablonozás alapbólKell hozzá választani egy sablonmotort (mi nem használunk: JSON-t adunk vissza)
KÉSZEN KAPOD ✓Útvonalkezelés ✓Middleware-lánc ✓Válasz-segédfüggvények ✓A kérés törzsének feldolgozása ✓Statikus fájlok kiszolgálása ✓Központi hibakezelés ✓Kész middleware-ek ezrei NEKED KELL MEGOLDANOD —Adatbázis-kezelés3. blokk —Validáció3. blokk —Hitelesítés, jogosultság4. blokk —Projektszerkezet7. fejezet —Sablonozásnem használjuk Ez szabadság és felelősség egyszerre. A Nest.js (5. blokk) ezzel szemben mindent előír.
2. ábra — Amit az Express elvégez helyetted, és amit külön kell megoldanod.
EZ ELŐNY VAGY HÁTRÁNY?

Mindkettő. Az Express nem szól bele, hogyan építed fel a projektet — ez szabadság, de felelősség is. Ezért fogunk a 7. fejezetben rétegekre bontani egy tudatosan kialakított szerkezetet. (Van szigorúbb keretrendszer is: ilyen a Nest.js, amit az 5. blokkban veszünk — az mindent előír.)

2Telepítés

Az Express npm-csomag, tehát a projektbe telepítjük:

mkdir express-proba
cd express-proba
npm init -y
npm install express

Ellenőrzés — a package.json kiegészült:

{
  "name": "express-proba",
  "version": "1.0.0",
  "type": "module",
  "main": "index.js",
  "dependencies": {
    "express": "^5.2.1"
  }
}
NE FELEJTSD EL A "type": "module" SORT!

Enélkül az import nem működik (SyntaxError: Cannot use import statement outside a module). Ha npm init -y volt, ezt kézzel kell hozzáadnod — lásd az 1. blokk 3. fejezetét.

A telepített verzió: Express 5.2.1. A csomag Node 18-as vagy újabb verziót igényel — a mi Node 24-esünk bőven megfelel.

3Az első Express-alkalmazás

import express from "express";              // 1

const app = express();                      // 2

app.get("/", (req, res) => {                // 3
  res.send("Szia az Expressről!");          // 4
});

app.listen(3000, () => {                    // 5
  console.log("A szerver fut: http://localhost:3000");
});

Indítás:

node --watch index.js

Sorról sorra

SorMit csinál?Miért így?
1Behúzza az Express csomagotNincs node: előtag, mert ez npm-csomag, nem beépített modul
2Létrehozza az alkalmazástAz express() egy függvényt ad vissza, ami egyben objektum is — ehhez adjuk hozzá az útvonalakat
3Regisztrál egy útvonalat„Ha GET kérés jön a / címre, futtasd ezt a függvényt”
4Elküldi a választA res.send() beállítja a Content-Type-ot és lezárja a választ — nincs külön res.end()
5Elindítja a szervertUgyanaz, mint a http modulnál: a callback egyszer fut le
A req ÉS A res ISMERŐS

Ugyanaz a két objektum, mint a http modulban — az Express csak kiegészíti őket új metódusokkal (res.json, res.status, req.params…). Az eredeti tulajdonságok (req.method, req.url, req.headers) továbbra is elérhetők.

Mi történik az app.listen() mögött?

Ez a sor a háttérben pontosan ezt csinálja:

// amit az app.listen(3000) valójában tesz:
import http from "node:http";
const server = http.createServer(app);   // az app maga a kérés-feldolgozó függvény!
server.listen(3000);

Az app egy függvény, amely (req, res) paramétereket vár — pontosan olyan, mint amit a http.createServer() elvár. Az Express tehát nem helyettesíti a Node szerverét, hanem kiszolgáló függvényt ad neki.

EZ NEM ELMÉLETI ÉRDEKESSÉG

A 8. fejezetben, amikor tesztelni fogjuk az alkalmazást, pontosan ezt használjuk ki: az app-ot át tudjuk adni tesztelő eszköznek anélkül, hogy tényleg elindítanánk egy szervert a 3000-es porton.

4A válaszküldés eszközei

Az Express négy metódust ad, amit naponta használni fogsz. A Content-Type fejlécet mindegyik automatikusan beállítja — de nem mindegy, melyiket választod.

MetódusMit csinál?Content-Type
res.send(érték)Elküldi az értéket; a típusból következtet a formátumraszövegnél: text/html, objektumnál: application/json
res.json(objektum)Kifejezetten JSON-t küldmindig application/json
res.status(kód)Csak beállítja a státuszkódot — láncolni kell utána—
res.sendStatus(kód)Beállítja a kódot és azonnal küldtext/plain

A tényleges viselkedés

Ezek valódi, kipróbált válaszok (Express 5.2.1):

Amit írszStátuszContent-TypeTörzs
res.send("Szia!")200text/html; charset=utf-8Szia!
res.send({ a: 1 })200application/json; charset=utf-8{"a":1}
res.send([1, 2, 3])200application/json; charset=utf-8[1,2,3]
res.send(42)200application/json; charset=utf-842
res.json({ a: 1 })200application/json; charset=utf-8{"a":1}
res.status(201).json({ ok: true })201application/json; charset=utf-8{"ok":true}
res.sendStatus(204)204— (nincs)(üres)
res.sendStatus(404)404text/plain; charset=utf-8Not Found

Figyeld meg a táblázat két meglepetését. Az egyik, hogy a szám és a tömb is JSON-ként megy el — csak a szöveg az, ami HTML-nek számít. A másik, hogy a res.sendStatus(404) az angol Not Found szöveget küldi törzsként, sima szövegként — ez API-ban nem az, amit a kliens vár.

FIGYELEM — A res.send("szöveg") HTML-T MOND!

Sokan meglepődnek: a Content-Type: text/html, nem text/plain. Ennek történeti oka van (a böngészőnek szánt tartalom volt az alapeset). API-nál ezért mindig res.json()-t használunk, még akkor is, ha csak egy rövid üzenetet küldünk:

res.status(404).json({ error: { message: "Nincs ilyen termék." } });

A státuszkód mindig a küldés ELŐTT

res.status(201).json(termek);      // ✅ helyes — láncolva
res.json(termek).status(201);      // ❌ hiába: a válasz már elment

A res.status() csak beállít, nem küld. A tényleges küldés a json() / send() hívásnál történik — utána már késő módosítani.

MIT KÜLDESZ? a napi döntés Adatot, 200-as kóddal res.json(adat) Adatot, MÁS kóddal (201, 404…) res.status(kód).json(adat) Csak kódot, törzs nélkül (204) res.sendStatus(204) ÉS A res.send()? API-ban gyakorlatilag soha nem kell. Szöveggel HTML-t mond, ami félrevezeti a klienst; objektummal pedig ugyanazt csinálja, mint a res.json() — csak kevésbé egyértelműen. Ökölszabály: amíg JSON API-t írsz, a res.json() és a res.sendStatus() elég mindenre. (A res.send()-del a 7. fejezetben, a statikus fájloknál találkozunk újra.)
3. ábra — Melyik válaszküldő metódus való a helyzethez?
EMLÉKEZTETŐ AZ 1. BLOKK 2. FEJEZETÉBŐL

A helyes státuszkódok: 200 sikeres lekérésre, 201 létrehozásra (+ Location fejléc), 204 törlésre, 400/422 hibás adatra, 401 és 403 a hitelesítéshez és jogosultsághoz, 404 nemlétező erőforrásra.

Melyik válaszküldő metódus?

Hat helyzet a webshop API-ból. Válaszd ki, melyik metódussal válaszolnál — ez az a döntés, amit naponta többször meghozol majd.

1 / 6Helyes: 0
…

5Express 4 vs. 5 — amit tudnod kell

Ez a szakasz meg fogja spórolni neked az első órák felét. Az interneten és a régebbi könyvekben található példák szinte kivétel nélkül Express 4-esek, és néhány dolog az 5-ösben hibát dob.

A leggyakoribb csapda: a joker (*) útvonal

Rengeteg tutorial így írja a 404-kezelőt:

app.get("*", (req, res) => {          // ❌ Express 5-ben HIBA!
  res.status(404).send("Nincs ilyen oldal");
});

Express 5-ben ez azonnal elszáll, már induláskor — a szerver el sem indul:

PathError [TypeError]: Missing parameter name at index 1: *; visit https://git.new/pathToRegexpError for info
    at consumeUntil (…\node_modules\path-to-regexp\dist\index.js:108:27)
    …
  originalPath: '*'
A hibaüzenet részeMit jelent?
PathError [TypeError]A hiba saját neve PathError, a típusa viszont TypeError — a Node így írja ki a kettőt együtt
Missing parameter name„Hiányzik a paraméter neve” — a jokernek nevet kell adni
at index 1A minta hányadik karakterénél akadt el a feldolgozás
git.new/pathToRegexpErrorA mintákat feldolgozó könyvtár saját magyarázó oldala
originalPath: '*'Az a minta, amit te írtál — ebből tudod, melyik sorodat kell javítani

Miért? Mert az 5-ös verzió új útvonal-értelmezőt használ, amelyben a * önmagában nem érvényes: minden jokernek nevet kell adni.

A helyes megoldás — kétféleképpen:

// 1) Útvonal nélküli middleware a lánc VÉGÉN — ez a legegyszerűbb
app.use((req, res) => {
  res.status(404).json({ error: { message: "Nincs ilyen végpont." } });
});

// 2) Nevesített joker, ha tényleg kell az útvonal
app.get("/{*barmi}", (req, res) => {
  res.status(404).json({ error: { message: "Nincs ilyen végpont." } });
});

A 404-kezelő helye (a lánc legvégén) a 8. fejezet témája — itt csak a szintaxis a lényeg. Az útvonalminták teljes Express 5-ös szabályrendszere pedig a következő fejezetben jön.

Ugyanaz a kód régen és most

Express 4 — amit a neten találszNEM MŰKÖDIK
app.del("/api/products/:id", (req, res) => {
  const id = req.param("id");
  res.json(204, { torolve: id });
});

app.get("*", (req, res) =>
  res.status(404).send("Nincs ilyen"));
Express 5 — ahogy mi írjukHELYES
app.delete("/api/products/:id", (req, res) => {
  const id = req.params.id;
  res.sendStatus(204);
});

app.use((req, res) =>
  res.status(404).json(
    { error: { message: "Nincs ilyen végpont." } }));

Négy változás egyetlen példában: app.del → app.delete, req.param() → req.params.id, res.json(kód, obj) → külön hívás, és a joker helyett app.use(). Vedd észre azt is, hogy a 204 mellé nem küldünk törzset — a 204 épp azt jelenti, hogy nincs tartalom.

Egyéb eltérések

Express 4Express 5Mit tegyél?
app.del(…)Megszűntapp.delete(…)
req.param("nev")Megszűntreq.params.nev, req.query.nev vagy req.body.nev
res.json(status, obj)Megszűntres.status(status).json(obj)
app.get("*")Hibát dobapp.use(fv) vagy app.get("/{*nev}")
Aszinkron hiba elveszettAutomatikusan a hibakezelőhöz megyNem kell try/catch minden útvonalba
body-parser csomag kellettBeépített: express.json()Ne telepítsd a body-parser-t

Az aszinkron hibák — a legjobb újdonság

Express 4-ben ez a kód csendben elszállt, és a kérés örökre lógott:

app.get("/api/products", async (req, res) => {
  const termekek = await adatbazisbolLekerdez();   // ha ez hibát dob…
  res.json(termekek);
});

Express 5-ben a keretrendszer elkapja, és továbbadja a hibakezelőnek. Ellenőrizve: egy szándékosan dobott hiba az async útvonalban eljut a hibakezelő middleware-hez, és 500-as válasz születik belőle:

GET /hiba  →  500  application/json  {"error":"szandekos hiba"}
AKKOR NEM KELL try/catch?

De — csak nem mindenhova. Ha csak azt akarod, hogy a hiba 500-as válasz legyen, elég az automatikus továbbadás. Ha viszont saját üzenetet vagy más státuszkódot szeretnél (például 404-et, ha nincs ilyen termék), akkor kell a try/catch. A 8. fejezetben ezt részletesen kidolgozzuk.

Express 4 vagy 5?

Hét kódrészlet régi tutorialokból. Döntsd el mindegyikről, hogy Express 5-ben működik-e. A visszajelzés megadja a javítást is.

1 / 7Helyes: 0
…

6Projektszerkezet: app.js és index.js

Eddig egyetlen fájlban volt minden. Már most érdemes kettéválasztani:

app.jsMIT TUD?
// app.js — az alkalmazás FELÉPÍTÉSE
import express from "express";

const app = express();
app.use(express.json());

app.get("/", (req, res) => {
  res.json({ uzenet: "Szia az Expressről!" });
});

export default app;   // NEM indítjuk el
index.jsHOL FUT?
// index.js — a szerver INDÍTÁSA
import app from "./app.js";

const PORT = process.env.PORT || 3000;

app.listen(PORT, () => {
  console.log(
    `A szerver fut: http://localhost:${PORT}`);
});

Miért érdemes szétválasztani?

OkMagyarázat
TesztelhetőségA teszt az app-ot használja, és nem indít szervert — nem foglal portot, gyorsabb, és párhuzamosan is futtatható
Egy fájl, egy felelősségAz app.js azt mondja meg, mit tud az alkalmazás; az index.js azt, hol fut
Több indítási módUgyanaz az app futhat éles szerveren, tesztben vagy serverless környezetben
A .js KITERJESZTÉS KÖTELEZŐ

Az importban: from "./app.js". ESM-ben ez nem elhagyható — lásd az 1. blokk 3. fejezetét. Enélkül ERR_MODULE_NOT_FOUND hibát kapsz.

7A port és a környezeti változók

const PORT = process.env.PORT || 3000;
RészMit csinál?
process.env.PORTA környezetből olvassa a portot (.env fájlból vagy a szolgáltatótól)
|| 3000Ha nincs megadva, a 3000-est használja — így a projekt beállítás nélkül is elindul

Használat .env fájllal (1. blokk, 3. fejezet):

# .env
PORT=4000
"scripts": {
  "dev": "node --watch --env-file=.env index.js"
}
MIÉRT NEM ÉGETJÜK BE A PORTOT?

Mert éles környezetben a szolgáltató mondja meg, melyik porton kell figyelni — jellemzően éppen a PORT környezeti változóban. Ha beégetnéd, a program ott el sem indulna. Ráadásul így iskolai gépen is könnyű másik portra váltani, ha a 3000-es foglalt.

8Gyakori hibák

Hibaüzenet / tünetMit jelent?Megoldás
Cannot use import statement outside a moduleHiányzik a "type": "module"Vedd fel a package.json-ba
Cannot find module 'express'Nincs telepítve a csomagnpm install express
PathError [TypeError]: Missing parameter name at index 1: *Express 4-es joker útvonal (app.get("*"))app.use(fv) vagy app.get("/{*nev}")
EADDRINUSE: address already in useA port foglalt (fut még egy szerver)Állítsd le, vagy válts portot a .env-ben
app.del is not a functionExpress 4-es metódusapp.delete(…)
A válasz text/html, pedig JSON-t vártálres.send("szöveg") volt használvares.json({ … })
A státuszkód mindig 200res.json(…).status(…) sorrendres.status(201).json(…)
req.body az undefinedHiányzik az express.json()app.use(express.json()); — az 5. fejezetben részletesen

9Feladatok

Elméleti

F1⭐Mit ad, mit nem?

Döntsd el, az Express adja-e készen, vagy külön kell megoldanod:

  • a) Útvonalkezelés
  • b) Adatbázis-lekérdezés
  • c) JSON-válasz küldése
  • d) Jelszó-hashelés
  • e) Statikus fájlok kiszolgálása
  • f) A kérés törzsének feldolgozása
  • g) Adatok validálása
F2⭐Melyik metódus?

Melyiket használnád, és miért?

  • a) Egy terméklista visszaadása
  • b) Sikeres törlés jelzése, tartalom nélkül
  • c) Új termék létrehozásának visszaigazolása az elkészült objektummal
  • d) Hibaüzenet küldése 404-es kóddal
F3⭐⭐Express 4-es kód javítása

Egy régi tutorialból másoltad ezt. Mi a három hiba, és mi lesz a tünetük?

app.del("/api/products/:id", (req, res) => {
  const id = req.param("id");
  res.json(204, { torolve: id });
});

app.get("*", (req, res) => res.status(404).send("Nincs ilyen"));
F4⭐⭐Szétválasztás

Miért érdemes az app.js és az index.js fájlt szétválasztani? Írj három érvet, és mindegyikhez egy konkrét helyzetet, amikor előny!

F5⭐⭐⭐Mi van a felszín alatt?

Magyarázd el saját szavaiddal, mit jelent az, hogy „az app maga egy kérés-feldolgozó függvény”. Miért tudja az http.createServer(app) hívás átvenni? Mihez lesz ez jó a tesztelésnél?

Gyakorlati

G1⭐Az első alkalmazás

Hozz létre egy új projektet, telepítsd az Expresst, és készíts egy szervert, amely a / címen JSON-ban visszaadja a nevedet és az aktuális dátumot. Indítsd npm run dev-vel (node --watch)!

G2⭐⭐Válaszküldés

Készíts négy végpontot, amelyek rendre a res.send() szöveggel, a res.send() objektummal, a res.json() és a res.sendStatus() metódussal válaszolnak. Nézd meg REST Clienttel mindegyik Content-Type fejlécét és státuszkódját, és készíts belőle egy táblázatot!

G3⭐⭐Státuszkódok

Készíts végpontokat, amelyek rendre 200, 201, 204, 404 és 500 kóddal válaszolnak, egységes JSON hibaformátummal. Próbáld ki mindet, és jegyezd fel az eredményt!

G4⭐⭐Port a környezetből

Vedd ki a portot .env fájlba, és állítsd be a dev scriptet --env-file-lal. Bizonyítsd be, hogy a .env átírásával másik porton indul a szerver!

G5⭐⭐⭐Szétválasztás

Bontsd szét a projektedet app.js és index.js fájlra a 6. szakasz szerint. Ellenőrizd, hogy minden ugyanúgy működik. Magyarázd el egy mondatban, mit tartalmaz a két fájl!

10Önellenőrző kvíz

0 / 10 megválaszolva

11Összegzés

  1. Az Express nem cseréli le a http modult, hanem ráépül: kényelmi réteg a kérés-válasz kezeléshez.
  2. Amit ad: útvonalkezelés, middleware, válasz-segédfüggvények, törzs-feldolgozás, statikus fájlok, hibakezelés. Amit nem: adatbázis, validáció, hitelesítés, projektszerkezet.
  3. Az app maga egy kérés-feldolgozó függvény — ezért tudja az http.createServer(app) átvenni. Ez teszi lehetővé a tesztelést szerverindítás nélkül.
  4. API-nál mindig res.json()-t használunk, mert a res.send("szöveg") text/html fejléccel megy el.
  5. A státuszkód a küldés előtt áll: res.status(201).json(…) — fordítva már késő.
  6. Az Express 5 néhány 4-es szokást megszüntetett: app.del, req.param(), res.json(status, obj), és az app.get("*") hibát dob. Cserébe az aszinkron hibákat automatikusan továbbítja a hibakezelőnek.
  7. Az alkalmazást (app.js) és a szerver indítását (index.js) szétválasztjuk, a portot pedig környezeti változóból vesszük.

12Fogalomtár

FogalomJelentés
ExpressA Node.js legelterjedtebb webes keretrendszere; a http modulra épül
Keretrendszer (framework)Kész szerkezet és eszközkészlet, amelybe a saját kódodat illeszted
express()Létrehozza az alkalmazásobjektumot
appMaga a kérés-feldolgozó függvény — ezt kapja meg a Node szervere
app.get(útvonal, kezelő)Útvonal regisztrálása egy metódusra
app.listen(port, fv)A szerver elindítása
res.send()Válasz küldése; a formátumot a típusból következteti
res.json()JSON-válasz küldése — API-nál ezt használjuk
res.status(kód)Státuszkód beállítása; láncolni kell egy küldő metódussal
res.sendStatus(kód)Státuszkód beállítása és azonnali küldés, törzs nélkül
process.envA környezeti változók objektuma
← Előző 2. Az első HTTP-szerver Node-dal