add CompactRecipePoint for loading recipe header data
This commit is contained in:
parent
380eb4cd21
commit
3638909761
8 changed files with 97 additions and 35 deletions
|
|
@ -1,11 +1,11 @@
|
||||||
meta {
|
meta {
|
||||||
name: getAllRecipes
|
name: getCompactRecipes
|
||||||
type: http
|
type: http
|
||||||
seq: 5
|
seq: 5
|
||||||
}
|
}
|
||||||
|
|
||||||
get {
|
get {
|
||||||
url: http://localhost:4000/recipe
|
url: http://localhost:4000/compact-recipe
|
||||||
body: none
|
body: none
|
||||||
auth: bearer
|
auth: bearer
|
||||||
}
|
}
|
||||||
28
src/controllers/CompactRecipeController.ts
Normal file
28
src/controllers/CompactRecipeController.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { CompactRecipeDto } from "../dtos/CompactRecipeDto.js";
|
||||||
|
import { RecipeEntity } from "../entities/RecipeEntity.js";
|
||||||
|
import { CompactRecipeDtoEntityMapper } from "../mappers/CompactRecipeDtoEntityMapper.js";
|
||||||
|
import { RecipeRepository } from "../repositories/RecipeRepository.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responsible for loading recipe header data
|
||||||
|
*/
|
||||||
|
export class CompactRecipeController {
|
||||||
|
constructor(
|
||||||
|
private repository: RecipeRepository,
|
||||||
|
private mapper: CompactRecipeDtoEntityMapper
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load list of all recipes
|
||||||
|
* @returns List of all recipes
|
||||||
|
*/
|
||||||
|
async getAllCompactRecipes() {
|
||||||
|
const recipeEntities: RecipeEntity[] = await this.repository.findAll();
|
||||||
|
// @todo load instruction steps, ingredient groups and ingredients before mapping!
|
||||||
|
let recipeDtos: CompactRecipeDto[] = [];
|
||||||
|
recipeEntities.forEach(recipeEntity => {
|
||||||
|
recipeDtos.push(this.mapper.toDto(recipeEntity));
|
||||||
|
});
|
||||||
|
return recipeDtos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
import { RecipeDto } from "../dtos/RecipeDto.js";
|
import { RecipeDto } from "../dtos/RecipeDto.js";
|
||||||
import { RecipeDtoEntityMapper } from "../mappers/RecipeDtoEntityMapper.js";
|
import { RecipeDtoEntityMapper } from "../mappers/RecipeDtoEntityMapper.js";
|
||||||
import { RecipeRepository } from "../repositories/RecipeRepository.js";
|
import { RecipeRepository } from "../repositories/RecipeRepository.js";
|
||||||
import { RecipeEntity } from "../entities/RecipeEntity.js";
|
|
||||||
import { ValidationError } from "../errors/httpErrors.js";
|
import { ValidationError } from "../errors/httpErrors.js";
|
||||||
import { RecipeInstructionStepDto } from "../dtos/RecipeInstructionStepDto.js";
|
import { RecipeInstructionStepDto } from "../dtos/RecipeInstructionStepDto.js";
|
||||||
import { RecipeIngredientGroupDto } from "../dtos/RecipeIngredientGroupDto.js";
|
import { RecipeIngredientGroupDto } from "../dtos/RecipeIngredientGroupDto.js";
|
||||||
import { RecipeIngredientDto } from "../dtos/RecipeIngredientDto.js";
|
import { RecipeIngredientDto } from "../dtos/RecipeIngredientDto.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controls all user specific actions
|
* Controls all recipe specific actions
|
||||||
*/
|
*/
|
||||||
export class RecipeController {
|
export class RecipeController {
|
||||||
constructor(
|
constructor(
|
||||||
|
|
@ -16,19 +15,6 @@ export class RecipeController {
|
||||||
private mapper: RecipeDtoEntityMapper
|
private mapper: RecipeDtoEntityMapper
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
/**
|
|
||||||
* Load list of all recipes
|
|
||||||
* @returns List of all recipes
|
|
||||||
*/
|
|
||||||
async getAllRecipes() {
|
|
||||||
const recipeEntities : RecipeEntity[] = await this.repository.findAll();
|
|
||||||
let recipeDtos: RecipeDto[] = [];
|
|
||||||
recipeEntities.forEach(recipeEntity => {
|
|
||||||
recipeDtos.push(this.mapper.toDto(recipeEntity));
|
|
||||||
});
|
|
||||||
return recipeDtos;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new recipe
|
* Create a new recipe
|
||||||
* @param dto RecipeDto containing the new recipe
|
* @param dto RecipeDto containing the new recipe
|
||||||
|
|
@ -48,7 +34,7 @@ export class RecipeController {
|
||||||
* @param dto RecipeDTO
|
* @param dto RecipeDTO
|
||||||
* @returns true if the recipe is valid
|
* @returns true if the recipe is valid
|
||||||
*/
|
*/
|
||||||
protected isRecipeDtoValid(dto: RecipeDto): boolean {
|
private isRecipeDtoValid(dto: RecipeDto): boolean {
|
||||||
|
|
||||||
return dto.title !== undefined
|
return dto.title !== undefined
|
||||||
&& dto.title.length !== 0
|
&& dto.title.length !== 0
|
||||||
|
|
@ -64,7 +50,7 @@ export class RecipeController {
|
||||||
* @param ingredientGroups Array of ingredient groups
|
* @param ingredientGroups Array of ingredient groups
|
||||||
* @returns true if all ingredient groups are valid
|
* @returns true if all ingredient groups are valid
|
||||||
*/
|
*/
|
||||||
protected isIngredientGroupsValid(ingredientGroups: RecipeIngredientGroupDto[] | undefined): boolean {
|
private isIngredientGroupsValid(ingredientGroups: RecipeIngredientGroupDto[] | undefined): boolean {
|
||||||
return ingredientGroups !== undefined
|
return ingredientGroups !== undefined
|
||||||
&& ingredientGroups.length !== 0
|
&& ingredientGroups.length !== 0
|
||||||
&& ingredientGroups.every(group => {
|
&& ingredientGroups.every(group => {
|
||||||
|
|
@ -80,7 +66,7 @@ export class RecipeController {
|
||||||
* @param ingredients Array if ingredients
|
* @param ingredients Array if ingredients
|
||||||
* @returns true if the ingredient list is valid
|
* @returns true if the ingredient list is valid
|
||||||
*/
|
*/
|
||||||
isIngredientsValid(ingredients: RecipeIngredientDto[] | undefined): boolean {
|
private isIngredientsValid(ingredients: RecipeIngredientDto[] | undefined): boolean {
|
||||||
return ingredients !== undefined
|
return ingredients !== undefined
|
||||||
&& ingredients.length !== 0
|
&& ingredients.length !== 0
|
||||||
&& ingredients.every(ingredient => {
|
&& ingredients.every(ingredient => {
|
||||||
|
|
@ -92,7 +78,7 @@ export class RecipeController {
|
||||||
* @param ingredient RecipeIngredientDto
|
* @param ingredient RecipeIngredientDto
|
||||||
* @returns true if the ingredient is valid
|
* @returns true if the ingredient is valid
|
||||||
*/
|
*/
|
||||||
isIngredientValid(ingredient: RecipeIngredientDto): boolean {
|
private isIngredientValid(ingredient: RecipeIngredientDto): boolean {
|
||||||
return ingredient !== null
|
return ingredient !== null
|
||||||
&& ingredient.sortOrder !== undefined
|
&& ingredient.sortOrder !== undefined
|
||||||
&& ingredient.name !== undefined
|
&& ingredient.name !== undefined
|
||||||
|
|
@ -106,7 +92,7 @@ export class RecipeController {
|
||||||
* @param instructions Array if instruction step DTOs
|
* @param instructions Array if instruction step DTOs
|
||||||
* @returns Boolean indicating whether the instruction steps are valid
|
* @returns Boolean indicating whether the instruction steps are valid
|
||||||
*/
|
*/
|
||||||
protected isInstructionsValid(instructions: RecipeInstructionStepDto[] | undefined): boolean {
|
private isInstructionsValid(instructions: RecipeInstructionStepDto[] | undefined): boolean {
|
||||||
return instructions !== undefined
|
return instructions !== undefined
|
||||||
&& instructions.length !== 0
|
&& instructions.length !== 0
|
||||||
&& instructions.every(step => {
|
&& instructions.every(step => {
|
||||||
|
|
|
||||||
11
src/dtos/CompactRecipeDto.ts
Normal file
11
src/dtos/CompactRecipeDto.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
import { AbstractDto } from "./AbstractDto.js";
|
||||||
|
/**
|
||||||
|
* DTO describing the essential header data of a recipe
|
||||||
|
* Used to populate lists
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class CompactRecipeDto extends AbstractDto {
|
||||||
|
title!: string;
|
||||||
|
// @todo add resource and rating here once implemented!
|
||||||
|
}
|
||||||
27
src/endpoints/CompactRecipePoint.ts
Normal file
27
src/endpoints/CompactRecipePoint.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { Router } from "express";
|
||||||
|
import { asyncHandler } from "../utils/asyncHandler.js";
|
||||||
|
import { RecipeRepository } from "../repositories/RecipeRepository.js";
|
||||||
|
import { CompactRecipeController } from "../controllers/CompactRecipeController.js";
|
||||||
|
import { CompactRecipeDtoEntityMapper } from "../mappers/CompactRecipeDtoEntityMapper.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles all recipe related routes
|
||||||
|
*/
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
// Inject repo + mapper here
|
||||||
|
const recipeRepository = new RecipeRepository();
|
||||||
|
const compactRecipeMapper = new CompactRecipeDtoEntityMapper();
|
||||||
|
const compactRecipeController = new CompactRecipeController(recipeRepository, compactRecipeMapper);
|
||||||
|
/**
|
||||||
|
* Load header data of all recipes
|
||||||
|
*/
|
||||||
|
router.get(
|
||||||
|
"/",
|
||||||
|
asyncHandler(async (req, res) => {
|
||||||
|
const response = await compactRecipeController.getAllCompactRecipes();
|
||||||
|
res.status(201).json(response);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
export default router;
|
||||||
|
|
@ -9,7 +9,7 @@ import { RecipeIngredientGroupDtoEntityMapper } from "../mappers/RecipeIngredien
|
||||||
import { RecipeInstructionStepDtoEntityMapper } from "../mappers/RecipeInstructionStepDtoEntityMapper.js";
|
import { RecipeInstructionStepDtoEntityMapper } from "../mappers/RecipeInstructionStepDtoEntityMapper.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles all user related routes
|
* Handles all recipe related routes
|
||||||
*/
|
*/
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
|
|
@ -21,7 +21,6 @@ const recipeInstructionStepMapper = new RecipeInstructionStepDtoEntityMapper();
|
||||||
const recipeMapper = new RecipeDtoEntityMapper(recipeInstructionStepMapper, recipeIngredientGroupMapper);
|
const recipeMapper = new RecipeDtoEntityMapper(recipeInstructionStepMapper, recipeIngredientGroupMapper);
|
||||||
const recipeController = new RecipeController(recipeRepository, recipeMapper);
|
const recipeController = new RecipeController(recipeRepository, recipeMapper);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new recipe
|
* Create new recipe
|
||||||
*/
|
*/
|
||||||
|
|
@ -34,15 +33,4 @@ router.post(
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* Load all recipes
|
|
||||||
*/
|
|
||||||
router.get(
|
|
||||||
"/",
|
|
||||||
asyncHandler(async (req, res) => {
|
|
||||||
const response = await recipeController.getAllRecipes();
|
|
||||||
res.status(201).json(response);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
@ -4,6 +4,7 @@ import dotenv from "dotenv";
|
||||||
import { AppDataSource } from "./data-source.js";
|
import { AppDataSource } from "./data-source.js";
|
||||||
import authRoutes, { authBasicRoute } from "./endpoints/AuthPoint.js";
|
import authRoutes, { authBasicRoute } from "./endpoints/AuthPoint.js";
|
||||||
import userRoutes from "./endpoints/UserPoint.js";
|
import userRoutes from "./endpoints/UserPoint.js";
|
||||||
|
import compactRecipeRoutes from "./endpoints/CompactRecipePoint.js";
|
||||||
import recipeRoutes from "./endpoints/RecipePoint.js";
|
import recipeRoutes from "./endpoints/RecipePoint.js";
|
||||||
import { errorHandler } from "./middleware/errorHandler.js";
|
import { errorHandler } from "./middleware/errorHandler.js";
|
||||||
import { authentication } from "./middleware/authenticationMiddleware.js";
|
import { authentication } from "./middleware/authenticationMiddleware.js";
|
||||||
|
|
@ -33,6 +34,7 @@ async function startServer() {
|
||||||
app.use(authBasicRoute, authRoutes);
|
app.use(authBasicRoute, authRoutes);
|
||||||
app.use("/user", userRoutes);
|
app.use("/user", userRoutes);
|
||||||
app.use("/recipe", recipeRoutes);
|
app.use("/recipe", recipeRoutes);
|
||||||
|
app.use("/compact-recipe", compactRecipeRoutes);
|
||||||
|
|
||||||
// Error handling for all rest-calls
|
// Error handling for all rest-calls
|
||||||
// must come last!
|
// must come last!
|
||||||
|
|
|
||||||
20
src/mappers/CompactRecipeDtoEntityMapper.ts
Normal file
20
src/mappers/CompactRecipeDtoEntityMapper.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { CompactRecipeDto } from "../dtos/CompactRecipeDto.js";
|
||||||
|
import { RecipeEntity } from "../entities/RecipeEntity.js";
|
||||||
|
import { AbstractDtoEntityMapper } from "./AbstractDtoEntityMapper.js";
|
||||||
|
|
||||||
|
export class CompactRecipeDtoEntityMapper extends AbstractDtoEntityMapper<RecipeEntity,CompactRecipeDto>{
|
||||||
|
|
||||||
|
toDto(entity: RecipeEntity): CompactRecipeDto {
|
||||||
|
const dto = new CompactRecipeDto();
|
||||||
|
this.mapBaseEntityToDto(entity, dto);
|
||||||
|
|
||||||
|
dto.title = entity.title;
|
||||||
|
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
toEntity(dto: CompactRecipeDto): RecipeEntity {
|
||||||
|
throw new Error("Mapping CompactRecipeDto to RecipeEntity is not allowed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue