\section{Middleware}

\begin{frame}[shrink=15]{Mi az a middleware?}
  \begin{block}{Definíció}
    Függvény HTTP kérés-válasz között, hozzáfér \texttt{req}, \texttt{res}, \texttt{next}-hez.
  \end{block}
  \begin{itemize}
    \item Láncolható
    \item Kérés előfeldolgozás, válasz utófeldolgozás
    \item Kérés megszakítható
  \end{itemize}
\end{frame}

\begin{frame}[shrink=15]{Middleware működése}
  \begin{center}
    \begin{tikzpicture}[node distance=1.4cm, auto]
      \node (browser) [rectangle, draw, text width=1.5cm, text centered] {Browser};
      \node (mw1) [rectangle, draw, right of=browser, xshift=1cm, text width=2cm, text centered] {MW 1\\Logger};
      \node (mw2) [rectangle, draw, right of=mw1, xshift=1.5cm, text width=2cm, text centered] {MW 2\\Auth};
      \node (route) [rectangle, draw, right of=mw2, xshift=1.5cm, text width=1.5cm, text centered] {Route};
      
      \draw[->, thick] (browser) -- node[above] {Req} (mw1);
      \draw[->, thick] (mw1) -- node[above] {\tiny next()} (mw2);
      \draw[->, thick] (mw2) -- node[above] {\tiny next()} (route);
      \draw[->, thick, dashed] (route) -- node[below] {Res} (browser);
    \end{tikzpicture}
  \end{center}
  \begin{alertblock}{Fontos}
    \texttt{next()} nélkül kérés megáll!
  \end{alertblock}
\end{frame}

\begin{frame}[shrink=15]{Middleware típusok}
  \begin{enumerate}
    \item \textbf{Application-level}: \texttt{app.use()}
    \item \textbf{Router-level}: \texttt{router.use()}
    \item \textbf{Error-handling}: \texttt{(err, req, res, next)}
    \item \textbf{Built-in}: \texttt{express.json()}, \texttt{express.static()}
    \item \textbf{Third-party}: \texttt{cors}, \texttt{helmet}, \texttt{morgan}
  \end{enumerate}
\end{frame}

\begin{frame}[fragile,shrink=20]{Logger middleware}
  \begin{verbatim}
const logger = (req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  next();
};

app.use(logger);

app.get('/', (req, res) => {
  res.json({ msg: 'Hello' });
});

// Kimenet:
// [2026-02-24T10:30:15.000Z] GET /
  \end{verbatim}
\end{frame}

\begin{frame}[fragile,shrink=20]{Request timing middleware}
  \begin{verbatim}
const timer = (req, res, next) => {
  req.startTime = Date.now();
  res.on('finish', () => {
    const duration = Date.now() - req.startTime;
    console.log(`${req.method} ${req.url} - ${duration}ms`);
  });
  next();
};

app.use(timer);

// GET /api/users - 145ms
  \end{verbatim}
\end{frame}

\begin{frame}[fragile,shrink=20]{Validation middleware}
  \begin{verbatim}
const validateEmail = (req, res, next) => {
  const { email } = req.body;
  const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  
  if (!email || !re.test(email)) {
    return res.status(400).json({ error: 'Invalid email' });
  }
  next();
};

app.post('/register', validateEmail, (req, res) => {
  res.json({ success: true });
});
  \end{verbatim}
\end{frame}

\begin{frame}[fragile,shrink=20]{Auth middleware}
  \begin{verbatim}
const auth = (req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1];
  
  if (!token) {
    return res.status(401).json({ error: 'Token required' });
  }
  
  try {
    const decoded = jwt.verify(token, SECRET);
    req.user = decoded;
    next();
  } catch (err) {
    res.status(403).json({ error: 'Invalid token' });
  }
};

app.get('/protected', auth, (req, res) => {
  res.json({ user: req.user });
});
  \end{verbatim}
\end{frame}

\begin{frame}[fragile,shrink=20]{Role-based middleware}
  \begin{verbatim}
const requireRole = (role) => {
  return (req, res, next) => {
    if (req.user.role !== role) {
      return res.status(403).json({ error: 'Forbidden' });
    }
    next();
  };
};

app.delete('/user/:id', auth, requireRole('admin'), (req, res) => {
  res.json({ deleted: true });
});
  \end{verbatim}
\end{frame}

\begin{frame}[fragile,shrink=20]{Error handling middleware}
  \begin{verbatim}
// Mindig utolsóként!
app.use((err, req, res, next) => {
  console.error(err.stack);
  
  res.status(err.status || 500).json({
    error: err.message || 'Internal Server Error'
  });
});

// Használat
app.get('/error', (req, res, next) => {
  const err = new Error('Something broke!');
  err.status = 500;
  next(err);
});
  \end{verbatim}
\end{frame}

\begin{frame}[fragile,shrink=20]{CORS middleware}
  \begin{verbatim}
const cors = require('cors');

// Minden origin engedélyezése
app.use(cors());

// Specifikus beállítás
app.use(cors({
  origin: 'https://frontend.com',
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE']
}));
  \end{verbatim}
\end{frame}

\begin{frame}[shrink=15]{Built-in middleware}
  \begin{itemize}
    \item \texttt{express.json()}: JSON body parsing
    \item \texttt{express.urlencoded()}: URL-encoded body parsing
    \item \texttt{express.static()}: Static fájlok kiszolgálása
  \end{itemize}
  \begin{exampleblock}{Használat}
    \texttt{app.use(express.json());}\\
    \texttt{app.use(express.static('public'));}
  \end{exampleblock}
\end{frame}

\begin{frame}[shrink=15]{Third-party middleware}
  \begin{description}
    \item[helmet] HTTP security headers
    \item[morgan] HTTP request logger
    \item[compression] Response compression (gzip)
    \item[cookie-parser] Cookie parsing
    \item[express-session] Session kezelés
    \item[passport] Authentication
  \end{description}
\end{frame}

\begin{frame}[shrink=15]{Middleware best practices}
  \begin{enumerate}
    \item Mindig hívd meg \texttt{next()}-et (vagy küldjél választ)
    \item Error middleware utolsóként
    \item Sorrendiség számít!
    \item Global middleware-ek előre (\texttt{cors}, \texttt{helmet})
    \item Route-specifikus middleware-ek közvetlenül route-hoz
    \item Async middleware-eknél használj try-catch-et
  \end{enumerate}
\end{frame}
