Some checks failed
Deploy to Test Environment / deploy-to-test (push) Failing after 7m32s
105 lines
4.2 KiB
TypeScript
105 lines
4.2 KiB
TypeScript
// src/routes/recipe.routes.ts
|
|
import { Router, type Request, type Response, type NextFunction } from 'express';
|
|
import crypto from 'crypto';
|
|
import * as db from '../services/db/index.db';
|
|
import { logger } from '../services/logger.server';
|
|
|
|
const router = Router();
|
|
|
|
/**
|
|
* GET /api/recipes/by-sale-percentage - Get recipes based on the percentage of their ingredients on sale.
|
|
*/
|
|
router.get('/by-sale-percentage', async (req: Request, res: Response, next: NextFunction) => {
|
|
const minPercentageStr = req.query.minPercentage as string || '50.0';
|
|
const minPercentage = parseFloat(minPercentageStr);
|
|
|
|
if (isNaN(minPercentage) || minPercentage < 0 || minPercentage > 100) {
|
|
return res.status(400).json({ message: 'Query parameter "minPercentage" must be a number between 0 and 100.' });
|
|
}
|
|
try {
|
|
const recipes = await db.recipeRepo.getRecipesBySalePercentage(minPercentage);
|
|
res.json(recipes);
|
|
} catch (error) {
|
|
logger.error('Error fetching recipes in /api/recipes/by-sale-percentage:', { error });
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* GET /api/recipes/by-sale-ingredients - Get recipes by the minimum number of sale ingredients.
|
|
*/
|
|
router.get('/by-sale-ingredients', async (req: Request, res: Response, next: NextFunction) => {
|
|
try {
|
|
const minIngredientsStr = req.query.minIngredients as string || '3';
|
|
const minIngredients = parseInt(minIngredientsStr, 10);
|
|
|
|
if (isNaN(minIngredients) || minIngredients < 1) {
|
|
return res.status(400).json({ message: 'Query parameter "minIngredients" must be a positive integer.' });
|
|
}
|
|
const recipes = await db.recipeRepo.getRecipesByMinSaleIngredients(minIngredients);
|
|
res.json(recipes);
|
|
} catch (error) {
|
|
logger.error('Error fetching recipes in /api/recipes/by-sale-ingredients:', { error });
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* GET /api/recipes/by-ingredient-and-tag - Find recipes by a specific ingredient and tag.
|
|
*/
|
|
router.get('/by-ingredient-and-tag', async (req: Request, res: Response, next: NextFunction) => {
|
|
try {
|
|
const { ingredient, tag } = req.query;
|
|
if (!ingredient || !tag) {
|
|
return res.status(400).json({ message: 'Both "ingredient" and "tag" query parameters are required.' });
|
|
}
|
|
const recipes = await db.recipeRepo.findRecipesByIngredientAndTag(ingredient as string, tag as string);
|
|
res.json(recipes);
|
|
} catch (error) {
|
|
logger.error('Error fetching recipes in /api/recipes/by-ingredient-and-tag:', { error });
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* GET /api/recipes/:recipeId - Get a single recipe by its ID, including ingredients and tags.
|
|
*/
|
|
router.get('/:recipeId', async (req: Request, res: Response, next: NextFunction) => {
|
|
try {
|
|
const recipeId = parseInt(req.params.recipeId, 10);
|
|
if (isNaN(recipeId)) {
|
|
return res.status(400).json({ message: 'Invalid recipe ID provided.' });
|
|
}
|
|
const recipe = await db.recipeRepo.getRecipeById(recipeId);
|
|
if (!recipe) {
|
|
return res.status(404).json({ message: `Recipe with ID ${recipeId} not found.` });
|
|
}
|
|
res.json(recipe);
|
|
} catch (error) {
|
|
logger.error(`Error fetching recipe ID ${req.params.recipeId}:`, { error });
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Recipe-specific error handling middleware.
|
|
* This should be the last middleware added to this router.
|
|
* It catches any errors passed by `next(error)` in the routes above.
|
|
*/
|
|
router.use((error: Error, req: Request, res: Response, next: NextFunction) => {
|
|
// Generate a unique ID for this specific error occurrence.
|
|
const errorId = crypto.randomBytes(4).toString('hex');
|
|
|
|
// Log the full error details on the server for debugging.
|
|
logger.error(`[API /recipes] Error ID: ${errorId} - An unhandled error occurred in the recipe router.`, {
|
|
error: error.message,
|
|
stack: error.stack,
|
|
url: req.originalUrl,
|
|
method: req.method,
|
|
});
|
|
|
|
// Send a generic, safe response to the client.
|
|
res.status(500).json({ message: `An internal server error occurred. Please try again later. If the problem persists, please reference error ID: ${errorId}` });
|
|
});
|
|
|
|
export default router; |