[added] - new routes

This commit is contained in:
Swapnil Bendal
2024-12-18 15:08:10 +05:30
parent ac0d3012c7
commit b8feb4bf89
9 changed files with 64 additions and 27 deletions

View File

@@ -6,4 +6,9 @@ import tseslint from 'typescript-eslint';
export default tseslint.config(
eslint.configs.recommended,
tseslint.configs.recommended,
{
rules: {
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
}
},
);

View File

@@ -4,9 +4,9 @@ import config from "./config/config";
import morgan from "./config/morgan";
import path from 'path';
import logger from './config/logger';
import ApiError from './utils/helper/ApiError';
import error from './middleware/error';
import routes from './routes';
import ApiError from './utils/helper/ApiError';
class App {
private app: Application;
@@ -38,8 +38,12 @@ class App {
}
private initializeErrorHandling(): void {
this.app.use(error.errorConverter);
this.app.use(error.errorHandler);
this.app.use(error.errorConverter);
this.app.use((req, res, next) => {
console.log('Request passed through middleware.');
next();
});
}
public listen(port: number): ReturnType<typeof this.app.listen> {

View File

@@ -35,6 +35,16 @@ export class ProductController {
res.status(200).json(new ApiResponse(200, data, 'Products retrieved successfully'));
}
@AsyncHandler()
async onGetByIDProducts(req: Request, res: Response) {
const data = await this.interactor.getByIdProduct(Number(req.params.id));
if (!data) {
res.status(200).json(new ApiResponse(200, null, 'No products found'));
return;
}
res.status(200).json(new ApiResponse(200, data, 'Products retrieved successfully'));
}
@AsyncHandler()
async onUpdateStock(req: Request, res: Response) {
const data = await this.interactor.updateStock(parseInt(`${req.params.id}`, 10), parseInt(`${req.body.stock}`, 10));

View File

@@ -38,5 +38,8 @@ export class ProductInteractor implements IProductInteractor {
async getProducts(limit: number, offset: number): Promise<Product[]> {
return await this.repository.find(limit, offset)
}
async getByIdProduct(id: number): Promise<Product> {
return await this.repository.findById(id)
}
}

View File

@@ -1,7 +1,8 @@
import { Product } from "../entities/Product";
export interface IProductInteractor {
createProduct(input: Partial<Product>): Promise<Product>;
updateStock(id: number, stock: number): Promise<Product>;
getProducts(limit: number, offset: number): Promise<Product[]>;
}
createProduct(input: Partial<Product>): Promise<Product>;
updateStock(id: number, stock: number): Promise<Product>;
getProducts(limit: number, offset: number): Promise<Product[]>;
getByIdProduct(id: number): Promise<Product>;
}

View File

@@ -4,4 +4,5 @@ export interface IProductRepository {
create(data: Product): Promise<Product>;
update(id: number, data: Partial<Product>): Promise<Product>;
find(limit: number, offset: number): Promise<Product[]>;
findById(id: number): Promise<Product>;
}

View File

@@ -40,36 +40,44 @@ class error {
static errorHandler(
err: ApiError,
req: Request,
res: Response
res: Response,
_next: NextFunction // Retain this even if unused
): void {
let { statusCode, message } = err;
// Production environment: Ensure only operational errors are shown
if (config.env === 'production' && !err.isOperational) {
// Extract error details with fallback defaults
let { statusCode = 500, message = "Internal server error" } = err;
// Production: Ensure only operational errors reveal their messages
if (config.env === "production" && !err.isOperational) {
statusCode = 500;
message = "Internal server error";
message = "An unexpected error occurred";
}
// Attach error message to response locals for potential templating
res.locals.errorMessage = err.message;
// Response structure
// Construct the response payload
const response = {
code: statusCode,
message,
...(config.env === 'development' && { stack: err.stack })
...(config.env === "development" && err.stack && { stack: err.stack }), // Include stack trace only in development
...(err.errors && { errors: err.errors.map((e: Error) => e.message) }), // Include nested validation errors if any
};
// Log error in development
if (config.env === 'development') {
logger.error(err);
}
// Ensure the response is sent
res.status(statusCode).send(response);
// Don't call next() unless you want to propagate the error further
// If this is the final middleware, remove next()
// Log the error in all environments
logger.error({
message: err.message,
stack: err.stack,
statusCode,
errors: err.errors || [],
});
// Send the response
res.status(statusCode).json(response);
// Do not call `next()` here, as this is the final error handler.
}
}
export default error;

View File

@@ -40,4 +40,8 @@ export class ProductRepository implements IProductRepository {
order: { id: "ASC" }, // Optional: Add sorting for consistent results
});
}
async findById(id: number): Promise<Product> {
return await this.productRepository.findOneOrFail({ where: { id } });
}
}

View File

@@ -36,5 +36,6 @@ const productController = container.get<ProductController>(INTERFACE_TYPE.Produc
router.post('/', productController.onCreateProduct.bind(productController));
router.get('/', productController.onGetProducts.bind(productController));
router.patch('/:id', productController.onUpdateStock.bind(productController));
router.get('/:id', productController.onGetByIDProducts.bind(productController));
export default router;