feat(backend): sessions routes

This commit is contained in:
2026-05-20 20:59:48 +02:00
parent 9ed5fc39bd
commit 5de988d23b
2 changed files with 59 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ import type { Db } from './db/client.js';
import { ApiError } from './lib/errors.js';
import { cardsRouter } from './routes/cards.js';
import { lessonsRouter } from './routes/lessons.js';
import { sessionsRouter } from './routes/sessions.js';
export function createApp(db: Db): Express {
const app = express();
@@ -12,6 +13,7 @@ export function createApp(db: Db): Express {
app.get('/api/health', (_req, res) => res.json({ ok: true }));
app.use('/api/lessons', lessonsRouter(db));
app.use('/api', cardsRouter(db));
app.use('/api/sessions', sessionsRouter(db));
app.use((err: unknown, _req: Request, res: Response, _next: NextFunction) => {
if (err instanceof ZodError) {

View File

@@ -0,0 +1,57 @@
import { Router } from 'express';
import { attemptCreateSchema, sessionStartSchema } from '@flashcard/shared';
import type { Db } from '../db/client.js';
import {
abandonSession, endSession, getActiveSession, getNextItem, getSessionState,
recordAttempt, startSession,
} from '../services/sessions.js';
import { ApiError } from '../lib/errors.js';
export function sessionsRouter(db: Db): Router {
const r = Router();
r.post('/', async (req, res, next) => {
try {
const input = sessionStartSchema.parse(req.body);
res.status(201).json(await startSession(db, input));
} catch (e) { next(e); }
});
r.get('/active', async (_req, res, next) => {
try { res.json(await getActiveSession(db)); } catch (e) { next(e); }
});
r.get('/:id', async (req, res, next) => {
try {
const state = await getSessionState(db, Number(req.params.id));
if (!state) throw ApiError.notFound('Session');
res.json(state);
} catch (e) { next(e); }
});
r.get('/:id/next', async (req, res, next) => {
try {
const item = await getNextItem(db, Number(req.params.id));
if (!item) { res.json({ done: true }); return; }
res.json({ done: false, item });
} catch (e) { next(e); }
});
r.post('/:id/attempts', async (req, res, next) => {
try {
const input = attemptCreateSchema.parse(req.body);
await recordAttempt(db, Number(req.params.id), input);
res.status(204).end();
} catch (e) { next(e); }
});
r.post('/:id/end', async (req, res, next) => {
try { res.json(await endSession(db, Number(req.params.id))); } catch (e) { next(e); }
});
r.post('/:id/abandon', async (req, res, next) => {
try { res.json(await abandonSession(db, Number(req.params.id))); } catch (e) { next(e); }
});
return r;
}