346 lines
9.2 KiB
TeX
346 lines
9.2 KiB
TeX
% Routing
|
|
|
|
\section{Routing}
|
|
|
|
\begin{frame}{Mi a Routing?}
|
|
\begin{block}{Routing}
|
|
A kérések irányítása a megfelelő végpontokra (endpoint).
|
|
\end{block}
|
|
|
|
\begin{exampleblock}{Route komponensek}
|
|
\begin{itemize}
|
|
\item \textbf{HTTP metódus} - GET, POST, PUT, DELETE
|
|
\item \textbf{URL path} - /api/users, /api/products/:id
|
|
\item \textbf{Handler függvény} - (req, res) => \{\}
|
|
\end{itemize}
|
|
\end{exampleblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile,shrink=10]{Alapvető routing}
|
|
\begin{exampleblock}{Egyszerű route-ok}
|
|
\tiny
|
|
\begin{verbatim}
|
|
app.get('/api/users', (req, res) => {
|
|
res.json({ message: 'Get all users' });
|
|
});
|
|
|
|
app.post('/api/users', (req, res) => {
|
|
res.json({ message: 'Create user' });
|
|
});
|
|
|
|
app.put('/api/users/:id', (req, res) => {
|
|
res.json({ message: `Update user ${req.params.id}` });
|
|
});
|
|
|
|
app.delete('/api/users/:id', (req, res) => {
|
|
res.json({ message: `Delete user ${req.params.id}` });
|
|
});
|
|
\end{verbatim}
|
|
\end{exampleblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile,shrink=10]{Route paraméterek}
|
|
\begin{exampleblock}{:id paraméter}
|
|
\tiny
|
|
\begin{verbatim}
|
|
app.get('/api/users/:id', (req, res) => {
|
|
const userId = req.params.id;
|
|
res.json({ message: `User ID: ${userId}` });
|
|
});
|
|
|
|
// Több paraméter
|
|
app.get('/api/users/:userId/posts/:postId', (req, res) => {
|
|
const { userId, postId } = req.params;
|
|
res.json({ userId, postId });
|
|
});
|
|
\end{verbatim}
|
|
\end{exampleblock}
|
|
|
|
\begin{alertblock}{req.params}
|
|
URL-ben megadott dinamikus értékek.
|
|
\end{alertblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile,shrink=10]{Query paraméterek}
|
|
\begin{exampleblock}{Query string}
|
|
\tiny
|
|
\begin{verbatim}
|
|
// GET /api/users?page=1&limit=10&role=admin
|
|
|
|
app.get('/api/users', (req, res) => {
|
|
const { page, limit, role } = req.query;
|
|
|
|
res.json({
|
|
page: page || 1,
|
|
limit: limit || 10,
|
|
role: role
|
|
});
|
|
});
|
|
\end{verbatim}
|
|
\end{exampleblock}
|
|
|
|
\begin{alertblock}{req.query}
|
|
URL query string paraméterek (?key=value).
|
|
\end{alertblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile,shrink=15]{Query - Szűrés, Rendezés, Lapozás}
|
|
\begin{exampleblock}{GET /api/users?page=1\&limit=10\&sort=name\&role=admin}
|
|
\tiny
|
|
\begin{verbatim}
|
|
app.get('/api/users', (req, res) => {
|
|
let { page = 1, limit = 10, sort = 'id', role } = req.query;
|
|
|
|
page = parseInt(page);
|
|
limit = parseInt(limit);
|
|
|
|
let filteredUsers = users;
|
|
if (role) {
|
|
filteredUsers = filteredUsers.filter(u => u.role === role);
|
|
}
|
|
|
|
// Rendezés
|
|
filteredUsers.sort((a, b) => a[sort] > b[sort] ? 1 : -1);
|
|
|
|
// Lapozás
|
|
const start = (page - 1) * limit;
|
|
const paginatedUsers = filteredUsers.slice(start, start + limit);
|
|
|
|
res.json({ data: paginatedUsers, total: filteredUsers.length });
|
|
});
|
|
\end{verbatim}
|
|
\end{exampleblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile,shrink=15]{Express Router létrehozása}
|
|
\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' });
|
|
});
|
|
|
|
router.put('/:id', (req, res) => {
|
|
res.json({ message: `Update user ${req.params.id}` });
|
|
});
|
|
|
|
module.exports = router;
|
|
\end{verbatim}
|
|
\end{exampleblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile,shrink=10]{Router importálása}
|
|
\begin{exampleblock}{app.js}
|
|
\tiny
|
|
\begin{verbatim}
|
|
const express = require('express');
|
|
const app = express();
|
|
|
|
const userRoutes = require('./routes/users');
|
|
const productRoutes = require('./routes/products');
|
|
|
|
app.use(express.json());
|
|
app.use('/api/users', userRoutes);
|
|
app.use('/api/products', productRoutes);
|
|
|
|
app.listen(3000);
|
|
\end{verbatim}
|
|
\end{exampleblock}
|
|
|
|
\begin{alertblock}{Prefix}
|
|
Az \texttt{app.use('/api/users', userRoutes)} minden route-hoz hozzáadja a prefix-et.
|
|
\end{alertblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile,shrink=15]{Nested (beágyazott) route-ok}
|
|
\begin{exampleblock}{Hierarchikus erőforrások}
|
|
\tiny
|
|
\begin{verbatim}
|
|
// GET /api/users/:userId/posts
|
|
router.get('/:userId/posts', (req, res) => {
|
|
const { userId } = req.params;
|
|
res.json({ message: `Posts for user ${userId}` });
|
|
});
|
|
|
|
// GET /api/users/:userId/posts/:postId
|
|
router.get('/:userId/posts/:postId', (req, res) => {
|
|
const { userId, postId } = req.params;
|
|
res.json({ message: `User ${userId}, Post ${postId}` });
|
|
});
|
|
|
|
// POST /api/users/:userId/posts
|
|
router.post('/:userId/posts', (req, res) => {
|
|
const { userId } = req.params;
|
|
res.json({ message: `Create post for user ${userId}` });
|
|
});
|
|
\end{verbatim}
|
|
\end{exampleblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile,shrink=15]{Controller-ek használata (1/2)}
|
|
\begin{block}{Separation of Concerns}
|
|
Route-ok csak az útvonalat definiálják, Controller-ek tartalmazzák a logikát.
|
|
\end{block}
|
|
|
|
\begin{exampleblock}{controllers/user.controller.js}
|
|
\tiny
|
|
\begin{verbatim}
|
|
exports.getAllUsers = async (req, res) => {
|
|
try {
|
|
const users = await User.find();
|
|
res.json(users);
|
|
} catch (error) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
};
|
|
|
|
exports.getUserById = async (req, res) => {
|
|
try {
|
|
const user = await User.findById(req.params.id);
|
|
if (!user) return res.status(404).json({ error: 'Not found' });
|
|
res.json(user);
|
|
} catch (error) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
};
|
|
\end{verbatim}
|
|
\end{exampleblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile,shrink=10]{Controller-ek használata (2/2)}
|
|
\begin{exampleblock}{routes/users.js}
|
|
\tiny
|
|
\begin{verbatim}
|
|
const express = require('express');
|
|
const router = express.Router();
|
|
const userController = require('../controllers/user.controller');
|
|
|
|
router.get('/', userController.getAllUsers);
|
|
router.get('/:id', userController.getUserById);
|
|
router.post('/', userController.createUser);
|
|
router.put('/:id', userController.updateUser);
|
|
router.delete('/:id', userController.deleteUser);
|
|
|
|
module.exports = router;
|
|
\end{verbatim}
|
|
\end{exampleblock}
|
|
|
|
\begin{alertblock}{Tiszta kód}
|
|
Route fájlok rövidek, Controller-ekben a logika.
|
|
\end{alertblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile,shrink=10]{Middleware route-okban}
|
|
\begin{exampleblock}{Auth middleware route-ra}
|
|
\tiny
|
|
\begin{verbatim}
|
|
const auth = require('../middlewares/auth');
|
|
|
|
router.get('/protected', auth, (req, res) => {
|
|
res.json({ message: 'Protected data' });
|
|
});
|
|
|
|
router.post('/users', auth, validateUser, userController.createUser);
|
|
|
|
// Minden route-ra
|
|
router.use('/admin', auth, adminRoutes);
|
|
\end{verbatim}
|
|
\end{exampleblock}
|
|
|
|
\begin{alertblock}{Több middleware}
|
|
Több middleware függvényt is alkalmazhatsz sorban.
|
|
\end{alertblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile,shrink=15]{API verziókezelés (1/2)}
|
|
\begin{exampleblock}{Verziókezelés URL-ben}
|
|
\tiny
|
|
\begin{verbatim}
|
|
// V1 routes
|
|
const v1Routes = require('./routes/v1');
|
|
app.use('/api/v1', v1Routes);
|
|
|
|
// V2 routes
|
|
const v2Routes = require('./routes/v2');
|
|
app.use('/api/v2', v2Routes);
|
|
\end{verbatim}
|
|
\end{exampleblock}
|
|
|
|
\begin{exampleblock}{Struktúra}
|
|
\tiny
|
|
\begin{itemize}
|
|
\item routes/v1/index.js
|
|
\item routes/v1/users.js
|
|
\item routes/v1/products.js
|
|
\item routes/v2/index.js
|
|
\item routes/v2/users.js
|
|
\end{itemize}
|
|
\end{exampleblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile,shrink=10]{API verziókezelés (2/2)}
|
|
\begin{exampleblock}{routes/v1/index.js}
|
|
\tiny
|
|
\begin{verbatim}
|
|
const express = require('express');
|
|
const router = express.Router();
|
|
const userRoutes = require('./users');
|
|
const productRoutes = require('./products');
|
|
|
|
router.use('/users', userRoutes);
|
|
router.use('/products', productRoutes);
|
|
|
|
module.exports = router;
|
|
\end{verbatim}
|
|
\end{exampleblock}
|
|
|
|
\begin{exampleblock}{Használat}
|
|
\tiny
|
|
\begin{verbatim}
|
|
GET /api/v1/users
|
|
GET /api/v2/users
|
|
\end{verbatim}
|
|
\end{exampleblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}[shrink=10]{Route Best Practices}
|
|
\begin{alertblock}{Konvenciók}
|
|
\begin{enumerate}
|
|
\item Használj \textbf{főneveket}: \texttt{/users}, \texttt{/products}
|
|
\item Használj \textbf{többes számot}: \texttt{/users} $\checkmark$
|
|
\item \textbf{Hierarchia}: \texttt{/users/:userId/posts/:postId}
|
|
\item \textbf{Kisbetűs URL}: \texttt{/api/users} $\checkmark$
|
|
\item \textbf{Kötőjel}: \texttt{/user-profiles} $\checkmark$
|
|
\item \textbf{Verziókezelés}: \texttt{/api/v1/users}
|
|
\item \textbf{Szűrés query-vel}: \texttt{/users?role=admin}
|
|
\item \textbf{Ne igék}: \texttt{POST /users} $\checkmark$, \texttt{/createUser} $\times$
|
|
\end{enumerate}
|
|
\end{alertblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Összefoglalás - Routing}
|
|
\begin{itemize}
|
|
\item Routing = kérések irányítása végpontokra
|
|
\item Route paraméterek: \texttt{/users/:id} $\rightarrow$ \texttt{req.params.id}
|
|
\item Query paraméterek: \texttt{/users?page=1} $\rightarrow$ \texttt{req.query.page}
|
|
\item Express Router: moduláris route szervezés
|
|
\item Controller-ek: logika szétválasztása
|
|
\item Middleware: route-specifikus middleware-ek
|
|
\item Verziókezelés: /api/v1, /api/v2
|
|
\end{itemize}
|
|
|
|
\vspace{0.5cm}
|
|
|
|
\end{frame}
|