Skip to content

Commit

Permalink
improved error handling for stores route
Browse files Browse the repository at this point in the history
  • Loading branch information
Meirbek-dev committed Dec 16, 2024
1 parent b2b5d34 commit 123e10c
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 26 deletions.
2 changes: 0 additions & 2 deletions app/(root)/(routes)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
'use client';

import { useEffect, useCallback } from 'react';
import { useRouter } from 'next/navigation';

import { useStoreModal } from '@/hooks/use-store-modal';

// Компонент настройки магазина
const SetupPage = () => {
const router = useRouter();

// Используем селекторы из хука с мемоизацией
const { onOpen, isOpen } = useStoreModal(
Expand Down
1 change: 0 additions & 1 deletion app/(root)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { cache } from 'react';
import { z } from 'zod';

import prismadb from '@/lib/prismadb';
import { errorResponses } from '@/lib/error-responses';

// Кэширование запроса на получение магазина
const getStore = cache(async (userId: string) => {
Expand Down
81 changes: 58 additions & 23 deletions app/api/stores/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,51 +3,86 @@ import { NextResponse } from 'next/server';
import { z } from 'zod';

import prismadb from '@/lib/prismadb';
import { errorResponses } from '@/lib/error-responses';

// схема валидации для создания магазина
const createStoreSchema = z.object({
name: z.string().min(2, 'Имя должно содержать минимум 2 символа'),
name: z
.string()
.min(2, 'Имя должно содержать минимум 2 символа')
.max(50, 'Имя слишком длинное')
.trim()
.regex(/^[\p{L}\s-]+$/u, 'Имя может содержать только буквы, пробелы и дефисы'),
});

export async function POST(request: Request) {
try {
// Get user authentication status
const { userId } = await auth();

if (!userId) {
return new NextResponse('Unauthorized', { status: 401 });
return errorResponses.unauthorized();
}

// Parse and validate request body
const body = await request.json();
const validationResult = createStoreSchema.safeParse(body);

if (!validationResult.success) {
return new NextResponse(validationResult.error.message, { status: 400 });
return errorResponses.validationError(validationResult.error.message);
}

// Create store with validated data
const store = await prismadb.store.create({
data: {
name: validationResult.data.name,
userId,
},
select: {
id: true,
name: true,
createdAt: true,
},
// Проверка на лимит магазинов
const storesCount = await prismadb.store.count({
where: { userId },
});

return NextResponse.json(store, { status: 201 });
} catch (error) {
// Log error for monitoring but don't expose details
console.error('[STORES_POST]', error);
if (storesCount >= 7) {
return errorResponses.forbidden('Достигнут лимит магазинов (максимум 3)');
}

// Используем транзакцию для проверки дубликатов и создания магазина
const store = await prismadb.$transaction(async (tx) => {
// Проверка на дубликаты
const existingStore = await tx.store.findFirst({
where: {
userId,
name: validationResult.data.name,
},
select: { id: true },
});

return new NextResponse('Internal Server Error', {
status: 500,
if (existingStore) {
throw new Error('Магазин с таким именем уже существует');
}

return tx.store.create({
data: {
name: validationResult.data.name,
userId,
},
select: {
id: true,
name: true,
createdAt: true,
},
});
});

return NextResponse.json(store, {
status: 201,
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'no-cache, no-store, must-revalidate',
},
});
} catch (error) {
console.error('[STORES_POST]', error);
if (error instanceof Error) {
switch (error.message) {
case 'Магазин с таким именем уже существует':
return errorResponses.conflict(error.message);
default:
return errorResponses.serverError(error);
}
}
return errorResponses.serverError(error);
}
}

0 comments on commit 123e10c

Please sign in to comment.