feat(backend): sessions routes
This commit is contained in:
@@ -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) {
|
||||
|
||||
57
packages/backend/src/routes/sessions.ts
Normal file
57
packages/backend/src/routes/sessions.ts
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user