% Express.js REST API \section{Express.js REST API} \begin{frame}{Mi az Express.js?} \begin{block}{Express} Gyors, minimalista web framework Node.js-hez. \end{block} \begin{exampleblock}{Jellemzők} \begin{itemize} \item Egyszerű API \item Middleware-alapú \item Routing támogatás \item Template engine-ek \item Nagy közösség és sok plugin \end{itemize} \end{exampleblock} \end{frame} \begin{frame}[fragile,shrink=10]{Express telepítése} \begin{exampleblock}{NPM inicializálás és telepítés} \tiny \begin{verbatim} npm init -y npm install express \end{verbatim} \end{exampleblock} \begin{exampleblock}{package.json} \tiny \begin{verbatim} { "name": "my-api", "version": "1.0.0", "main": "server.js", "scripts": { "start": "node server.js", "dev": "nodemon server.js" }, "dependencies": { "express": "^4.18.2" } } \end{verbatim} \end{exampleblock} \end{frame} \begin{frame}[fragile,shrink=10]{Első Express szerver} \begin{exampleblock}{server.js} \tiny \begin{verbatim} const express = require('express'); const app = express(); const PORT = 3000; // Middleware app.use(express.json()); // Egyszerű route app.get('/', (req, res) => { res.json({ message: 'Hello, Express!' }); }); // Szerver indítása app.listen(PORT, () => { console.log(`Server running on http://localhost:${PORT}`); }); \end{verbatim} \end{exampleblock} \end{frame} \begin{frame}[fragile,shrink=10]{GET végpont} \begin{exampleblock}{Összes elem lekérdezése} \tiny \begin{verbatim} let users = [ {id: 1, name: 'Alice', email: 'alice@example.com'}, {id: 2, name: 'Bob', email: 'bob@example.com'} ]; app.get('/api/users', (req, res) => { res.json(users); }); \end{verbatim} \end{exampleblock} \begin{exampleblock}{Egy elem lekérdezése} \tiny \begin{verbatim} app.get('/api/users/:id', (req, res) => { const user = users.find(u => u.id === parseInt(req.params.id)); if (!user) { return res.status(404).json({ error: 'User not found' }); } res.json(user); }); \end{verbatim} \end{exampleblock} \end{frame} \begin{frame}[fragile,shrink=10]{POST végpont} \begin{exampleblock}{Új elem létrehozása} \tiny \begin{verbatim} app.post('/api/users', (req, res) => { const { name, email } = req.body; if (!name || !email) { return res.status(400).json({ error: 'Name and email required' }); } const newUser = { id: users.length + 1, name, email }; users.push(newUser); res.status(201).json(newUser); }); \end{verbatim} \end{exampleblock} \end{frame} \begin{frame}[fragile,shrink=10]{PUT és PATCH végpontok} \begin{exampleblock}{PUT - Teljes frissítés} \tiny \begin{verbatim} app.put('/api/users/:id', (req, res) => { const idx = users.findIndex(u => u.id === parseInt(req.params.id)); if (idx === -1) return res.status(404).json({ error: 'Not found' }); users[idx] = { id: parseInt(req.params.id), ...req.body }; res.json(users[idx]); }); \end{verbatim} \end{exampleblock} \begin{exampleblock}{PATCH - Részleges frissítés} \tiny \begin{verbatim} app.patch('/api/users/:id', (req, res) => { const user = users.find(u => u.id === parseInt(req.params.id)); if (!user) return res.status(404).json({ error: 'Not found' }); Object.assign(user, req.body); res.json(user); }); \end{verbatim} \end{exampleblock} \end{frame} \begin{frame}[fragile,shrink=10]{DELETE végpont} \begin{exampleblock}{Elem törlése} \tiny \begin{verbatim} app.delete('/api/users/:id', (req, res) => { const idx = users.findIndex(u => u.id === parseInt(req.params.id)); if (idx === -1) { return res.status(404).json({ error: 'User not found' }); } users.splice(idx, 1); res.status(204).send(); }); \end{verbatim} \end{exampleblock} \begin{alertblock}{204 No Content} Sikeres törlés esetén nem kell response body. \end{alertblock} \end{frame} \begin{frame}[fragile,shrink=10]{Middleware-ek} \begin{block}{Mi a Middleware?} Függvények, amelyek hozzáférnek a request és response objektumokhoz, és a \texttt{next()} függvényhez. \end{block} \begin{exampleblock}{Logger middleware} \tiny \begin{verbatim} app.use((req, res, next) => { console.log(`${req.method} ${req.url}`); next(); }); \end{verbatim} \end{exampleblock} \begin{exampleblock}{Auth middleware} \tiny \begin{verbatim} const authMiddleware = (req, res, next) => { const token = req.headers.authorization; if (!token) return res.status(401).json({ error: 'Unauthorized' }); next(); }; app.get('/api/protected', authMiddleware, (req, res) => { res.json({ data: 'Protected data' }); }); \end{verbatim} \end{exampleblock} \end{frame} \begin{frame}[fragile,shrink=10]{Error Handling} \begin{exampleblock}{Error handling middleware} \tiny \begin{verbatim} app.use((err, req, res, next) => { console.error(err.stack); res.status(500).json({ error: { message: err.message, code: 'INTERNAL_ERROR' } }); }); \end{verbatim} \end{exampleblock} \begin{exampleblock}{Try-catch async} \tiny \begin{verbatim} app.get('/api/users/:id', async (req, res, next) => { try { const user = await getUserById(req.params.id); if (!user) throw new Error('User not found'); res.json(user); } catch (error) { next(error); } }); \end{verbatim} \end{exampleblock} \end{frame} \begin{frame}[fragile,shrink=10]{Validáció Joi-val (1/2)} \begin{exampleblock}{Joi telepítése} \tiny \begin{verbatim} npm install joi \end{verbatim} \end{exampleblock} \begin{exampleblock}{Schema definiálás} \tiny \begin{verbatim} const Joi = require('joi'); const userSchema = Joi.object({ name: Joi.string().min(3).max(50).required(), email: Joi.string().email().required(), age: Joi.number().integer().min(0).max(120) }); \end{verbatim} \end{exampleblock} \end{frame} \begin{frame}[fragile,shrink=10]{Validáció Joi-val (2/2)} \begin{exampleblock}{Validáció használata} \tiny \begin{verbatim} app.post('/api/users', (req, res) => { const { error, value } = userSchema.validate(req.body); if (error) { return res.status(400).json({ error: error.details[0].message }); } // value a validált adat const newUser = { id: users.length + 1, ...value }; users.push(newUser); res.status(201).json(newUser); }); \end{verbatim} \end{exampleblock} \end{frame} \begin{frame}[fragile,shrink=15]{Express Router - Moduláris routing (1/2)} \begin{exampleblock}{routes/users.js} \tiny \begin{verbatim} const express = require('express'); const router = express.Router(); router.get('/', (req, res) => { res.json({ message: 'Get all users' }); }); router.get('/:id', (req, res) => { res.json({ message: `Get user ${req.params.id}` }); }); router.post('/', (req, res) => { res.json({ message: 'Create user' }); }); module.exports = router; \end{verbatim} \end{exampleblock} \end{frame} \begin{frame}[fragile,shrink=10]{Express Router - Moduláris routing (2/2)} \begin{exampleblock}{app.js - Router használata} \tiny \begin{verbatim} const express = require('express'); const app = express(); const userRoutes = require('./routes/users'); app.use(express.json()); app.use('/api/users', userRoutes); app.listen(3000); \end{verbatim} \end{exampleblock} \begin{alertblock}{Prefix} Az \texttt{app.use('/api/users', userRoutes)} prefix-szel látja el az összes route-ot. \end{alertblock} \end{frame} \begin{frame}{Összefoglalás - Express} \begin{itemize} \item Express = minimalista web framework \item Routing: GET, POST, PUT, PATCH, DELETE \item Middleware-ek: kérések feldolgozása \item Error handling: hibakezelő middleware \item Validáció: Joi vagy más library \item Router: moduláris útvonalkezelés \end{itemize} \vspace{0.5cm} \end{frame}