From 12670b713442be4b992f0bc1d1ced4d88800f847 Mon Sep 17 00:00:00 2001 From: gilles Date: Mon, 21 Sep 2026 17:58:59 +0200 Subject: [PATCH] =?UTF-8?q?feat(service):=20CardService=20g=C3=A9n=C3=A9ri?= =?UTF-8?q?que=20sur=20l'abstraction=20CardRepository?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/http.ts | 25 +++++++++++++ src/services/card-service-factory.ts | 6 ++++ src/services/card-service.ts | 52 ++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 src/lib/http.ts create mode 100644 src/services/card-service-factory.ts create mode 100644 src/services/card-service.ts diff --git a/src/lib/http.ts b/src/lib/http.ts new file mode 100644 index 0000000..bb0f077 --- /dev/null +++ b/src/lib/http.ts @@ -0,0 +1,25 @@ +import { NextResponse, type NextRequest } from 'next/server' +import { ZodError } from 'zod' +import { AppError, ValidationError } from '@/domain/errors' + +export function handleError(error: unknown): NextResponse { + if (error instanceof ZodError) { + return NextResponse.json( + { error: 'ValidationError', message: 'Payload invalide', issues: error.flatten() }, + { status: 400 }, + ) + } + if (error instanceof AppError) { + return NextResponse.json({ error: error.name, message: error.message }, { status: error.status }) + } + console.error(error) + return NextResponse.json({ error: 'InternalServerError', message: 'Erreur interne' }, { status: 500 }) +} + +export async function parseJsonBody(request: NextRequest): Promise { + try { + return await request.json() + } catch { + throw new ValidationError('Corps de requête invalide (JSON attendu)') + } +} \ No newline at end of file diff --git a/src/services/card-service-factory.ts b/src/services/card-service-factory.ts new file mode 100644 index 0000000..c0a2cd6 --- /dev/null +++ b/src/services/card-service-factory.ts @@ -0,0 +1,6 @@ +import { getCardRepository } from '@/config/card-repository-factory' +import { CardService } from './card-service' + +export function getCardService(): CardService { + return new CardService(getCardRepository()) +} \ No newline at end of file diff --git a/src/services/card-service.ts b/src/services/card-service.ts new file mode 100644 index 0000000..4c966bf --- /dev/null +++ b/src/services/card-service.ts @@ -0,0 +1,52 @@ +import type { Card, CardInput } from '@/domain/card' +import type { CardRepository } from '@/domain/card-repository' +import { NotFoundError } from '@/domain/errors' + +export class CardService { + constructor(private readonly repository: CardRepository) {} + + async list(): Promise { + return this.repository.findAll() + } + + async get(id: string): Promise { + const card = await this.repository.findById(id) + if (!card) { + throw new NotFoundError(`Carte ${id} introuvable`) + } + return card + } + + async create(input: CardInput): Promise { + return this.repository.create(input) + } + + async update(id: string, input: Partial): Promise { + const card = await this.repository.update(id, input) + if (!card) { + throw new NotFoundError(`Carte ${id} introuvable`) + } + return card + } + + async remove(id: string): Promise { + const deleted = await this.repository.delete(id) + if (!deleted) { + throw new NotFoundError(`Carte ${id} introuvable`) + } + } + + async random(theme?: string): Promise { + const card = theme + ? await this.repository.findRandomByTheme(theme) + : await this.repository.findRandom() + if (!card) { + throw new NotFoundError(theme ? `Aucune carte pour le thème ${theme}` : 'Aucune carte disponible') + } + return card + } + + async themes(): Promise { + return this.repository.findThemes() + } +} \ No newline at end of file