REST API v Node.js a Express.js

Proč stavět REST API v Node.js a Express.js

Node.js nabízí jednovláknový, event-driven běhový model s vysokou propustností I/O, což z něj činí ideální volbu pro síťové služby. Express.js je minimalistický framework, který přidává směrování, middleware architekturu a ekosystém rozšíření. Tato kombinace je vhodná pro RESTful API díky své jednoduchosti, výkonu a široké komunitě.

Zásady REST: zdroje, reprezentace, uniformní rozhraní

  • Zdroj: doménový objekt (např. /users, /orders), identifikovaný URI.
  • Reprezentace: typicky JSON s hlavičkou Content-Type: application/json.
  • Metody: GET (čtení), POST (vytvoření), PUT/PATCH (aktualizace), DELETE (mazání).
  • Bezstavovost: každý požadavek nese veškerý nutný kontext (autentizace, parametry).
  • Hypermedia a odkazy (volitelné): například pole _links s navigačními odkazy.
  • Cacheovatelnost: hlavičky ETag, Cache-Control, Last-Modified.

Struktura projektu: modularita a vrstvy

  • src/app.js: konfigurace Expressu, middleware, připojení rout.
  • src/routes/*.js: definice cest, mapování na kontrolery.
  • src/controllers/*.js: orchestraci požadavků, validace, odpovědi.
  • src/services/*.js: aplikační logika, doménová pravidla.
  • src/repositories/*.js: přístup k datům (databáze/externí API).
  • src/middlewares/*.js: autentizace, omezení frekvence, logování.
  • src/schemas/*.js: validační schémata (Joi/Zod).
  • src/config: proměnné prostředí, konfigurace.
  • tests/: integrační a jednotkové testy.

Inicializace a závislosti

  • Inicializace: npm init -y
  • Základní balíčky: npm i express dotenv
  • Bezpečnost a utilitky: npm i helmet cors morgan express-rate-limit
  • Validace: npm i zod nebo npm i joi
  • Testování: npm i -D jest supertest
  • Databáze (příklady): MongoDB npm i mongoose, PostgreSQL s ORM npm i @prisma/client (+ npm i -D prisma)

Spuštění Expressu a základní middleware

V souboru src/app.js nastavte jádro aplikace: JSON parsování, CORS, bezpečnostní hlavičky, omezení frekvence a logování.

  • app.use(express.json({ limit: "1mb" })) – bezpečné parsování těla požadavku.
  • app.use(cors()) – řízení povolených původů; ve výrobním prostředí omezení na specifické domény.
  • app.use(helmet()) – zabezpečující hlavičky (proti XSS, clickjackingu apod.).
  • app.use(morgan("combined")) – HTTP logování.
  • rateLimit({ windowMs: 60_000, max: 100 }) – omezení zneužití API.

Routing a kontrolery: čisté oddělení

Route definuje strukturu API; kontroler zpracovává validaci, volá službu a vrací odpověď.

  • Příklad cesty: router.get("/users", userController.list)
  • Kontroler načte req.query (filtry, stránkování), zavolá userService.findAll a vrátí odpověď 200 s JSON.
  • Pro vytvoření záznamu: router.post("/users", validate(userSchema), userController.create)

Validace vstupů a sanitace

Validujte vstupní query, params i body. Udržujte validační schémata v blízkosti doménových entit. Příklad se Zod:

  • const createUserSchema = z.object({ email: z.string().email(), name: z.string().min(2) })
  • function validate(schema) { return (req, res, next) => { const p = schema.safeParse(req.body); if (!p.success) return res.status(400).json({ errors: p.error.issues }); next(); } }

Chybové stavy a jednotný error handler

  • Vlastní chyby: class AppError extends Error { constructor(message, status=400, code="BAD_REQUEST"){ super(message); this.status=status; this.code=code; } }
  • Globální handler: app.use((err, req, res, next) => { const status = err.status || 500; res.status(status).json({ error: err.code || "INTERNAL", message: err.message }); })
  • Nezachycené chyby/promisy: připojte posluchače process.on("unhandledRejection") a process.on("uncaughtException").

Asynchronní řetězení: async/await a middleware

Zabalte asynchronní kontrolery do helperu, aby nedošlo k nezachyceným chybám: const asyncH = fn => (req,res,next) => Promise.resolve(fn(req,res,next)).catch(next). Používejte u všech kontrolerů.

Persistenční vrstva: Mongoose vs. Prisma

  • Mongoose (MongoDB): flexibilní modelování dokumentů; rychlý vývoj, schémata s validací na úrovni modelu.
  • Prisma (SQL): typová bezpečnost, migrace, složité dotazy; vhodné pro Postgres/MySQL/SQLite.
  • Repository pattern: userRepository.findById(id) kapsuluje detaily databáze a usnadňuje testování.

Filtrování, stránkování a řazení

  • Parametry: ?page=1&limit=20&sort=-createdAt&filter[name]=john
  • Výstup: metadata total, page, limit, hasNext a pole items.
  • Indexy: navrhujte podle nejčastějších dotazů; u MongoDB využijte compound indexy, u SQL btree/GIN podle typu dat.

Konvence HTTP kódů a odpovědí

  • 200 OK pro čtení, 201 Created s hlavičkou Location pro vytvoření zdroje.
  • 204 No Content pro úspěšné DELETE.
  • 400/422 pro chyby validace, 401 neautentizovaný, 403 bez oprávnění, 404 nenalezeno.
  • Konzistentní struktura chybové odpovědi: { "error": "VALIDATION_ERROR", "message": "...", "details": [...] }

Autentizace a autorizace (JWT, session, API klíče)

  • JWT: krátká platnost (např. 15 minut), refresh token s rotací; hlavička Authorization: Bearer <jwt>.
  • Scopes/role: claims scope nebo roles v JWT; middleware authorize("orders:read").
  • API klíče: určené pro server-to-server komunikaci; uložení zahashované, omezení (throttling) dle klíče.
  • Session: vhodné pro webové aplikace; preferujte cookie s atributy HttpOnly, SameSite, Secure.

Bezpečnost: CORS, hlavičky, rate-limit, input hardening

  • Omezte CORS na whitelist domén a povolte credentials pouze, pokud je to nezbytné.
  • helmet() upravuje klíčové hlavičky; doplňte Cross-Origin-Resource-Policy a Cross-Origin-Opener-Policy podle potřeby.
  • Rate-limit a zpomalovací strategie pro veřejné endpointy (přihlášení, registrace).
  • Sanitace vstupů: validace typů, whitelist polí, prevence NoSQL/SQL injection (parametrizace, whitelist operátorů).

Verzování API a kontrakty

  • URI verzování: /v1/..., /v2/... pro evoluční změny API.
  • Kontrakty: OpenAPI specifikace (yaml/json) generuje dokumentaci a slouží ke validaci schémat.
  • Deprecace: hlavičky Deprecation a Sunset s termínem ukončení a odkazem na migrační návod.

Dokumentace: OpenAPI/Swagger a živé testování

  • Generujte OpenAPI specifikace ručně nebo pomocí anotací; publikujte dokumentaci na /docs pouze v chráněném režimu.
  • Udržujte příklady požadavků, odpovědí a chybových scénářů; doplňte schémata do components/schemas.

Idempotence, bezpečné opakování a integrace

  • Idempotence: PUT by měl být idempotentní; u POST použijte idempotency key v hlavičce pro platební či externí operace.
  • Time-outy a retry: nastavte časová omezení na klientu i serveru; použijte exponenciální backoff.
  • Transakce: u SQL databází wrapperem; u DB bez transakcí využijte vzory jako outbox pattern a message broker.

Cacheování, ETag a podmíněné dotazy

  • ETag: generujte hash reprezentace zdroje; klient posílá If-None-Match, server vrací 304 Not Modified při nezměněných datech.
  • Cache-Control: vhodné pro veřejné read-only zdroje; invalidujte cache při změně obsahu.
  • Redis: krátkodobá cache opakovaných dotazů, metrik rate-limitu, session store.

Logování, korelace a observabilita

  • Strukturované logy: JSON s poli level, msg, timestamp, requestId.
  • Correlation ID: middleware generující request-id (např. z X-Request-ID hlavičky).
  • Health checks: endpointy /healthz (základní) a /readyz (závislosti na DB, cache).
  • Metriky: export do Promethea (latence, požadavky za sekundu, chybovost, využití paměti).

Testování: jednotkové, integrační a kontraktační

  • Jednotkové: izolujte služby a repozitáře (mock databáze).
  • Integrační: supertest proti instanci app bez síťového portu; připravte testovací data (seed).
  • Kontrakty: ověřte shodu s OpenAPI (pact testing, validace schémat).
  • Coverage: pokrývejte klíčové scénáře včetně okrajových případů (neplatné vstupy, prázdné výsledky, chybějící oprávnění).

Konfigurace a prostředí

  • 12-factor: konfigurace z process.env, nikoli pevně v kódu.
  • dotenv: používejte pouze pro lokální vývoj; ve výrobním prostředí získejte tajemství z secret manageru.
  • Feature flags: řízení funkcionality bez nutnosti redeploye aplikace.

Výkon a škálování

  • Node cluster nebo PM2 pro využití více CPU jader.
  • Reverse proxy (NGINX) s keep-alive, gzip/brotli kompresí; TLS terminace.
  • Optimalizace DB: správné indexy, omezené SELECTy, projekce polí.
  • Horizontální škálování: stateless instance, sticky sessions pouze pokud je to nezbytné.

Nasazení a CI/CD

  • Docker: multi-stage build (instalace, build, runtime s node:alpine), kontejner běžící pod neprivilegovaným uživatelem.
  • CI: lintování, testování, build image, skenování zranitelností, nasazení do stagingu/produktivního prostředí.
  • Migrace: automatické spuštění při startu (Prisma migrate deploy), strategie rollbacku.

Versioning databáze a evoluce schémat

  • Prisma migrations nebo Knex skripty pro SQL; pro MongoDB řízené změny skrze migrační nástroje (Migrate/Mongock).
  • Bezpečná evoluce: princip expand–migrate–contract (přidání pole → zapisování do obou verzí → čtení z nové → odstranění starého pole).

Pozor na č