codeweaver 1.0.15 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/settings.json +3 -0
- package/README.md +261 -56
- package/package.json +21 -15
- package/src/config.ts +56 -15
- package/src/constants.ts +6 -0
- package/src/main.ts +82 -0
- package/src/routers/{index.ts → index.router.ts} +2 -2
- package/src/routers/orders/dto/order.dto.ts +41 -0
- package/src/routers/orders/index.router.ts +157 -0
- package/src/routers/orders/order.controller.ts +178 -0
- package/src/routers/products/dto/product.dto.ts +37 -0
- package/src/routers/products/index.router.ts +200 -0
- package/src/routers/products/product.controller.ts +217 -0
- package/src/routers/users/dto/user.dto.ts +17 -3
- package/src/routers/users/index.router.ts +96 -0
- package/src/routers/users/user.controller.ts +138 -18
- package/src/swagger-options.ts +54 -0
- package/src/utilities/assign.ts +81 -0
- package/src/utilities/error-handling.ts +120 -0
- package/src/utilities/types.ts +23 -0
- package/tsconfig.json +6 -3
- package/tsconfig.paths.json +8 -0
- package/src/app.ts +0 -95
- package/src/routers/orders/index.ts +0 -40
- package/src/routers/products/index.ts +0 -167
- package/src/routers/users/index.ts +0 -81
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Zod schema for Order entity
|
|
5
|
+
* @typedef {Object} ZodOrder
|
|
6
|
+
* @property {number} id - Unique identifier (min 1)
|
|
7
|
+
* @property {number} userId - Associated user ID (min 1)
|
|
8
|
+
* @property {{productId: number, quantity: number}[]} products - Array of ordered products
|
|
9
|
+
* @property {"Processing"|"Delivered"|"Canceled"} status - Order status
|
|
10
|
+
* @property {number} total - Total price (min 1000)
|
|
11
|
+
* @property {Date} createdAt - Creation timestamp
|
|
12
|
+
* @property {Date} [canceledAt] - Cancellation timestamp
|
|
13
|
+
* @property {Date} [deliveredAt] - Delivery timestamp
|
|
14
|
+
*/
|
|
15
|
+
export const ZodOrder = z.object({
|
|
16
|
+
id: z.number().min(1).int(),
|
|
17
|
+
userId: z.number().min(1).int(),
|
|
18
|
+
products: z.array(
|
|
19
|
+
z.object({
|
|
20
|
+
productId: z.number().min(1).int(),
|
|
21
|
+
quantity: z.number().min(1).int(),
|
|
22
|
+
})
|
|
23
|
+
),
|
|
24
|
+
status: z.enum(["Processing", "Delivered", "Canceled"]),
|
|
25
|
+
total: z.number().min(1000),
|
|
26
|
+
createdAt: z.date(),
|
|
27
|
+
canceledAt: z.date().optional(),
|
|
28
|
+
deliveredAt: z.date().optional(),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export const ZodOrderCreationDto = ZodOrder.omit({
|
|
32
|
+
id: true,
|
|
33
|
+
status: true,
|
|
34
|
+
createdAt: true,
|
|
35
|
+
canceledAt: true,
|
|
36
|
+
deliveredAt: true,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export type Order = z.infer<typeof ZodOrder>;
|
|
40
|
+
export type OrderCreationDto = z.infer<typeof ZodOrderCreationDto>;
|
|
41
|
+
export type OrderDto = z.infer<typeof ZodOrder>;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { Router, Request, Response } from "express";
|
|
2
|
+
import asyncHandler from "express-async-handler";
|
|
3
|
+
import OrderController from "./order.controller";
|
|
4
|
+
|
|
5
|
+
const router = Router();
|
|
6
|
+
const orderController = new OrderController();
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @swagger
|
|
10
|
+
* /orders:
|
|
11
|
+
* post:
|
|
12
|
+
* summary: Create a new order
|
|
13
|
+
* description: Creates an order with user details and products.
|
|
14
|
+
* consumes:
|
|
15
|
+
* - application/json
|
|
16
|
+
* produces:
|
|
17
|
+
* - application/json
|
|
18
|
+
* parameters:
|
|
19
|
+
* - in: body
|
|
20
|
+
* name: order
|
|
21
|
+
* required: true
|
|
22
|
+
* schema:
|
|
23
|
+
* type: object
|
|
24
|
+
* required:
|
|
25
|
+
* - userId
|
|
26
|
+
* - products
|
|
27
|
+
* - total
|
|
28
|
+
* properties:
|
|
29
|
+
* userId:
|
|
30
|
+
* type: integer
|
|
31
|
+
* minimum: 1
|
|
32
|
+
* example: 1
|
|
33
|
+
* products:
|
|
34
|
+
* type: array
|
|
35
|
+
* description: Array of products in the order
|
|
36
|
+
* items:
|
|
37
|
+
* type: object
|
|
38
|
+
* required:
|
|
39
|
+
* - productId
|
|
40
|
+
* - quantity
|
|
41
|
+
* properties:
|
|
42
|
+
* productId:
|
|
43
|
+
* type: integer
|
|
44
|
+
* minimum: 1
|
|
45
|
+
* example: 3
|
|
46
|
+
* quantity:
|
|
47
|
+
* type: integer
|
|
48
|
+
* minimum: 1
|
|
49
|
+
* example: 2
|
|
50
|
+
* total:
|
|
51
|
+
* type: number
|
|
52
|
+
* minimum: 1000
|
|
53
|
+
* example: 250000
|
|
54
|
+
* responses:
|
|
55
|
+
* 201:
|
|
56
|
+
* description: Order created
|
|
57
|
+
*/
|
|
58
|
+
router.post(
|
|
59
|
+
"/",
|
|
60
|
+
asyncHandler(async (req: Request, res: Response) => {
|
|
61
|
+
const order = await orderController.create(req.body);
|
|
62
|
+
res.status(201).json(order);
|
|
63
|
+
})
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @swagger
|
|
68
|
+
* /orders:
|
|
69
|
+
* get:
|
|
70
|
+
* summary: Get all orders
|
|
71
|
+
* responses:
|
|
72
|
+
* 200:
|
|
73
|
+
* description: List of orders
|
|
74
|
+
*/
|
|
75
|
+
router.get(
|
|
76
|
+
"/",
|
|
77
|
+
asyncHandler(async (req: Request, res: Response) => {
|
|
78
|
+
const orders = await orderController.getAll();
|
|
79
|
+
res.json(orders);
|
|
80
|
+
})
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @swagger
|
|
85
|
+
* /orders/{id}:
|
|
86
|
+
* get:
|
|
87
|
+
* summary: Get order details
|
|
88
|
+
* parameters:
|
|
89
|
+
* - name: id
|
|
90
|
+
* in: path
|
|
91
|
+
* required: true
|
|
92
|
+
* description: Numeric ID of the order to retrieve
|
|
93
|
+
* type: integer
|
|
94
|
+
* example: 101
|
|
95
|
+
* responses:
|
|
96
|
+
* 200:
|
|
97
|
+
* description: Order details
|
|
98
|
+
*/
|
|
99
|
+
router.get(
|
|
100
|
+
"/:id",
|
|
101
|
+
asyncHandler(async (req: Request, res: Response) => {
|
|
102
|
+
const order = await orderController.get(req.params.id);
|
|
103
|
+
res.json(order);
|
|
104
|
+
})
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @swagger
|
|
109
|
+
* /orders/{id}/cancel:
|
|
110
|
+
* patch:
|
|
111
|
+
* summary: Cancel order
|
|
112
|
+
* parameters:
|
|
113
|
+
* - name: id
|
|
114
|
+
* in: path
|
|
115
|
+
* required: true
|
|
116
|
+
* description: Numeric ID of the order to cancel
|
|
117
|
+
* type: integer
|
|
118
|
+
* example: 101
|
|
119
|
+
* responses:
|
|
120
|
+
* 200:
|
|
121
|
+
* description: Order canceled successfully
|
|
122
|
+
*/
|
|
123
|
+
router.patch(
|
|
124
|
+
"/:id/cancel",
|
|
125
|
+
asyncHandler(async (req: Request, res: Response) => {
|
|
126
|
+
const order = await orderController.cancel(req.params.id);
|
|
127
|
+
res.json(order);
|
|
128
|
+
})
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @swagger
|
|
133
|
+
* /orders/{id}/deliver:
|
|
134
|
+
* patch:
|
|
135
|
+
* summary: Mark order as delivered
|
|
136
|
+
* parameters:
|
|
137
|
+
* - name: id
|
|
138
|
+
* in: path
|
|
139
|
+
* required: true
|
|
140
|
+
* description: Numeric ID of the order to deliver
|
|
141
|
+
* type: integer
|
|
142
|
+
* example: 101
|
|
143
|
+
* responses:
|
|
144
|
+
* 200:
|
|
145
|
+
* description: Order marked as delivered
|
|
146
|
+
* 400:
|
|
147
|
+
* description: Delivery is only available when the order is in processing status.
|
|
148
|
+
*/
|
|
149
|
+
router.patch(
|
|
150
|
+
"/:id/deliver",
|
|
151
|
+
asyncHandler(async (req: Request, res: Response) => {
|
|
152
|
+
const order = await orderController.deliver(req.params.id);
|
|
153
|
+
res.json(order);
|
|
154
|
+
})
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
export = router;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { memoizeAsync, onError, rateLimit, timeout } from "utils-decorators";
|
|
2
|
+
import {
|
|
3
|
+
Order,
|
|
4
|
+
OrderDto,
|
|
5
|
+
OrderCreationDto,
|
|
6
|
+
ZodOrderCreationDto,
|
|
7
|
+
} from "./dto/order.dto";
|
|
8
|
+
import { Validate, ZodInput } from "ts-zod4-decorators";
|
|
9
|
+
import { ResponseError } from "@/utilities/types";
|
|
10
|
+
import { parseId } from "@/utilities/error-handling";
|
|
11
|
+
import config from "@/config";
|
|
12
|
+
|
|
13
|
+
// Array to store orders (as a mock database)
|
|
14
|
+
const orders: Order[] = [
|
|
15
|
+
{
|
|
16
|
+
id: 1,
|
|
17
|
+
userId: 1,
|
|
18
|
+
products: [
|
|
19
|
+
{ productId: 2, quantity: 1 },
|
|
20
|
+
{ productId: 6, quantity: 2 },
|
|
21
|
+
],
|
|
22
|
+
status: "Delivered",
|
|
23
|
+
total: 14400,
|
|
24
|
+
createdAt: new Date("2024-01-15"),
|
|
25
|
+
deliveredAt: new Date("2024-02-10"),
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: 2,
|
|
29
|
+
userId: 3,
|
|
30
|
+
products: [
|
|
31
|
+
{ productId: 9, quantity: 1 },
|
|
32
|
+
{ productId: 7, quantity: 1 },
|
|
33
|
+
],
|
|
34
|
+
status: "Processing",
|
|
35
|
+
total: 36500,
|
|
36
|
+
createdAt: new Date("2024-03-20"),
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: 3,
|
|
40
|
+
userId: 2,
|
|
41
|
+
products: [
|
|
42
|
+
{ productId: 1, quantity: 1 },
|
|
43
|
+
{ productId: 4, quantity: 2 },
|
|
44
|
+
],
|
|
45
|
+
status: "Canceled",
|
|
46
|
+
total: 81000,
|
|
47
|
+
createdAt: new Date("2024-05-01"),
|
|
48
|
+
canceledAt: new Date("2024-05-03"),
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
function exceedHandler() {
|
|
53
|
+
const message = "Too much call in allowed window";
|
|
54
|
+
throw new ResponseError(message, 429);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getOrderErrorHandler(e: Error) {
|
|
58
|
+
const message = "Order not found.";
|
|
59
|
+
throw new ResponseError(message, 404, e.message);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Controller for handling order-related operations
|
|
64
|
+
* @class OrderController
|
|
65
|
+
* @desc Provides methods for order management including creation, status updates and retrieval
|
|
66
|
+
*/
|
|
67
|
+
export default class OrderController {
|
|
68
|
+
@rateLimit({
|
|
69
|
+
timeSpanMs: config.rateLimitTimeSpan,
|
|
70
|
+
allowedCalls: config.rateLimitAllowedCalls,
|
|
71
|
+
exceedHandler,
|
|
72
|
+
})
|
|
73
|
+
@Validate
|
|
74
|
+
/**
|
|
75
|
+
* Create a new order
|
|
76
|
+
* @param {OrderCreationDto} order - Order creation data
|
|
77
|
+
* @returns {Promise<Order>} Newly created order
|
|
78
|
+
*/
|
|
79
|
+
public async create(@ZodInput(ZodOrderCreationDto) order: OrderCreationDto) {
|
|
80
|
+
const newOrder = {
|
|
81
|
+
...order,
|
|
82
|
+
id: orders.length + 1,
|
|
83
|
+
createdAt: new Date(),
|
|
84
|
+
status: "Processing",
|
|
85
|
+
} satisfies Order;
|
|
86
|
+
|
|
87
|
+
orders.push(newOrder);
|
|
88
|
+
return newOrder;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@memoizeAsync(config.memoizeTime)
|
|
92
|
+
@timeout(config.timeout)
|
|
93
|
+
@rateLimit({
|
|
94
|
+
timeSpanMs: config.rateLimitTimeSpan,
|
|
95
|
+
allowedCalls: config.rateLimitAllowedCalls,
|
|
96
|
+
exceedHandler,
|
|
97
|
+
})
|
|
98
|
+
/**
|
|
99
|
+
* Retrieves all orders
|
|
100
|
+
* @returns List of orders
|
|
101
|
+
*/
|
|
102
|
+
public async getAll(): Promise<OrderDto[]> {
|
|
103
|
+
return orders;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@memoizeAsync(config.memoizeTime)
|
|
107
|
+
@rateLimit({
|
|
108
|
+
timeSpanMs: config.rateLimitTimeSpan,
|
|
109
|
+
allowedCalls: config.rateLimitAllowedCalls,
|
|
110
|
+
exceedHandler,
|
|
111
|
+
})
|
|
112
|
+
@onError({
|
|
113
|
+
func: getOrderErrorHandler,
|
|
114
|
+
})
|
|
115
|
+
/**
|
|
116
|
+
* Finds an order by its ID
|
|
117
|
+
* @param id - Order ID as string
|
|
118
|
+
* @returns Order details or error object if not found
|
|
119
|
+
*/
|
|
120
|
+
public async get(id: string): Promise<OrderDto> {
|
|
121
|
+
const orderId = parseId(id);
|
|
122
|
+
const order = orders.find((order) => order.id === orderId);
|
|
123
|
+
if (order == null) throw new ResponseError("User dose not exist.", 404);
|
|
124
|
+
return order satisfies Order;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@rateLimit({
|
|
128
|
+
timeSpanMs: config.rateLimitTimeSpan,
|
|
129
|
+
allowedCalls: config.rateLimitAllowedCalls,
|
|
130
|
+
exceedHandler,
|
|
131
|
+
})
|
|
132
|
+
/**
|
|
133
|
+
* Cancel an existing order
|
|
134
|
+
* @param {string} id - Order ID to cancel
|
|
135
|
+
* @returns {Promise<Order>} Updated order or error object
|
|
136
|
+
* @throws {ResponseError} 404 - Order not found
|
|
137
|
+
* @throws {ResponseError} 400 - Invalid ID format or invalid status for cancellation
|
|
138
|
+
*/
|
|
139
|
+
public async cancel(id: string): Promise<OrderDto> {
|
|
140
|
+
let order = await this.get(id);
|
|
141
|
+
if (order.status != "Processing") {
|
|
142
|
+
throw new ResponseError(
|
|
143
|
+
"Cancellation is not available unless the order is in processing status.",
|
|
144
|
+
400
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
order.status = "Canceled";
|
|
149
|
+
order.deliveredAt = new Date();
|
|
150
|
+
return order satisfies Order;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
@rateLimit({
|
|
154
|
+
timeSpanMs: config.rateLimitTimeSpan,
|
|
155
|
+
allowedCalls: config.rateLimitAllowedCalls,
|
|
156
|
+
exceedHandler,
|
|
157
|
+
})
|
|
158
|
+
/**
|
|
159
|
+
* Mark an order as delivered
|
|
160
|
+
* @param {string} id - Order ID to mark as delivered
|
|
161
|
+
* @returns {Promise<Order>} Updated order or error object
|
|
162
|
+
* @throws {ResponseError} 404 - Order not found
|
|
163
|
+
* @throws {ResponseError} 400 - Invalid ID format or invalid status for delivery
|
|
164
|
+
*/
|
|
165
|
+
public async deliver(id: string): Promise<OrderDto> {
|
|
166
|
+
let order = await this.get(id);
|
|
167
|
+
if (order.status != "Processing") {
|
|
168
|
+
throw new ResponseError(
|
|
169
|
+
"Delivery is only available when the order is in processing status.",
|
|
170
|
+
400
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
order.status = "Delivered";
|
|
175
|
+
order.deliveredAt = new Date();
|
|
176
|
+
return order satisfies Order;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Zod schema for Product entity
|
|
5
|
+
* @typedef {Object} ZodProduct
|
|
6
|
+
* @property {number} id - Unique identifier (min 1)
|
|
7
|
+
* @property {string} name - Product name (min 2 chars)
|
|
8
|
+
* @property {number} price - Product price (min 1000)
|
|
9
|
+
* @property {string} [description] - Optional description (min 10 chars)
|
|
10
|
+
* @property {string} category - Product category from predefined enum
|
|
11
|
+
* @property {number} stock - Available stock quantity (min 0)
|
|
12
|
+
*/
|
|
13
|
+
export const ZodProduct = z.object({
|
|
14
|
+
id: z.number().min(1).int(),
|
|
15
|
+
name: z.string().min(2),
|
|
16
|
+
price: z.number().min(1000),
|
|
17
|
+
description: z.string().min(10).optional(),
|
|
18
|
+
category: z.enum([
|
|
19
|
+
"Electronics",
|
|
20
|
+
"Appliances",
|
|
21
|
+
"Sports",
|
|
22
|
+
"Kitchen",
|
|
23
|
+
"Mobile Accessories",
|
|
24
|
+
"Computer Accessories",
|
|
25
|
+
"Home Appliances",
|
|
26
|
+
"Books",
|
|
27
|
+
]),
|
|
28
|
+
stock: z.number().min(0).int(),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export const ZodProductCreationDto = ZodProduct.omit({ id: true });
|
|
32
|
+
export const ZodProductUpdateDto = ZodProductCreationDto.partial();
|
|
33
|
+
|
|
34
|
+
export type Product = z.infer<typeof ZodProduct>;
|
|
35
|
+
export type ProductCreationDto = z.infer<typeof ZodProductCreationDto>;
|
|
36
|
+
export type ProductUpdateDto = z.infer<typeof ZodProductUpdateDto>;
|
|
37
|
+
export type ProductDto = z.infer<typeof ZodProduct>;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { Router, Request, Response } from "express";
|
|
2
|
+
import asyncHandler from "express-async-handler";
|
|
3
|
+
import ProductController from "./product.controller";
|
|
4
|
+
|
|
5
|
+
const router = Router();
|
|
6
|
+
const productController = new ProductController();
|
|
7
|
+
|
|
8
|
+
// CRUD Routes
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @swagger
|
|
12
|
+
* /products:
|
|
13
|
+
* post:
|
|
14
|
+
* summary: Create a product
|
|
15
|
+
* description: Create a new product.
|
|
16
|
+
* consumes:
|
|
17
|
+
* - application/json
|
|
18
|
+
* produces:
|
|
19
|
+
* - application/json
|
|
20
|
+
* parameters:
|
|
21
|
+
* - in: body
|
|
22
|
+
* name: product
|
|
23
|
+
* required: true
|
|
24
|
+
* schema:
|
|
25
|
+
* type: object
|
|
26
|
+
* required:
|
|
27
|
+
* - name
|
|
28
|
+
* - price
|
|
29
|
+
* - category
|
|
30
|
+
* - stock
|
|
31
|
+
* properties:
|
|
32
|
+
* id:
|
|
33
|
+
* type: integer
|
|
34
|
+
* example: 1
|
|
35
|
+
* name:
|
|
36
|
+
* type: string
|
|
37
|
+
* example: "New Product"
|
|
38
|
+
* price:
|
|
39
|
+
* type: number
|
|
40
|
+
* example: 1499
|
|
41
|
+
* description:
|
|
42
|
+
* type: string
|
|
43
|
+
* example: "This is a detailed description."
|
|
44
|
+
* category:
|
|
45
|
+
* type: string
|
|
46
|
+
* enum:
|
|
47
|
+
* - Electronics
|
|
48
|
+
* - Appliances
|
|
49
|
+
* - Sports
|
|
50
|
+
* - Kitchen
|
|
51
|
+
* - Mobile Accessories
|
|
52
|
+
* - Computer Accessories
|
|
53
|
+
* - Home Appliances
|
|
54
|
+
* - Books
|
|
55
|
+
* example: "Electronics"
|
|
56
|
+
* stock:
|
|
57
|
+
* type: integer
|
|
58
|
+
* example: 50
|
|
59
|
+
* responses:
|
|
60
|
+
* 201:
|
|
61
|
+
* description: Product created
|
|
62
|
+
*/
|
|
63
|
+
router.post(
|
|
64
|
+
"/",
|
|
65
|
+
asyncHandler(async (req: Request, res: Response) => {
|
|
66
|
+
const product = await productController.create(req.body);
|
|
67
|
+
res.status(201).json(product);
|
|
68
|
+
})
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @swagger
|
|
73
|
+
* /products:
|
|
74
|
+
* get:
|
|
75
|
+
* summary: Get all products
|
|
76
|
+
* responses:
|
|
77
|
+
* 200:
|
|
78
|
+
* description: A list of products
|
|
79
|
+
*/
|
|
80
|
+
router.get(
|
|
81
|
+
"/",
|
|
82
|
+
asyncHandler(async (req: Request, res: Response) => {
|
|
83
|
+
res.json(await productController.getAll());
|
|
84
|
+
})
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @swagger
|
|
89
|
+
* /products/{id}:
|
|
90
|
+
* get:
|
|
91
|
+
* summary: Get a product by ID
|
|
92
|
+
* parameters:
|
|
93
|
+
* - name: id
|
|
94
|
+
* in: path
|
|
95
|
+
* required: true
|
|
96
|
+
* description: The ID of the product
|
|
97
|
+
* schema:
|
|
98
|
+
* type: integer
|
|
99
|
+
* responses:
|
|
100
|
+
* 200:
|
|
101
|
+
* description: A product object
|
|
102
|
+
*/
|
|
103
|
+
router.get(
|
|
104
|
+
"/:id",
|
|
105
|
+
asyncHandler(async (req: Request, res: Response) => {
|
|
106
|
+
const product = await productController.get(req.params.id);
|
|
107
|
+
res.json(product);
|
|
108
|
+
})
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @swagger
|
|
113
|
+
* /products/{id}:
|
|
114
|
+
* put:
|
|
115
|
+
* summary: Update a product
|
|
116
|
+
* description: Update an existing product.
|
|
117
|
+
* consumes:
|
|
118
|
+
* - application/json
|
|
119
|
+
* produces:
|
|
120
|
+
* - application/json
|
|
121
|
+
* parameters:
|
|
122
|
+
* - name: id
|
|
123
|
+
* in: path
|
|
124
|
+
* required: true
|
|
125
|
+
* description: The ID of the product to update
|
|
126
|
+
* schema:
|
|
127
|
+
* type: integer
|
|
128
|
+
* - in: body
|
|
129
|
+
* name: product
|
|
130
|
+
* required: true
|
|
131
|
+
* schema:
|
|
132
|
+
* type: object
|
|
133
|
+
* properties:
|
|
134
|
+
* name:
|
|
135
|
+
* type: string
|
|
136
|
+
* example: "Updated Product"
|
|
137
|
+
* price:
|
|
138
|
+
* type: number
|
|
139
|
+
* example: 2000
|
|
140
|
+
* description:
|
|
141
|
+
* type: string
|
|
142
|
+
* example: "This is a detailed description."
|
|
143
|
+
* category:
|
|
144
|
+
* type: string
|
|
145
|
+
* enum:
|
|
146
|
+
* - Electronics
|
|
147
|
+
* - Appliances
|
|
148
|
+
* - Sports
|
|
149
|
+
* - Kitchen
|
|
150
|
+
* - Mobile Accessories
|
|
151
|
+
* - Computer Accessories
|
|
152
|
+
* - Home Appliances
|
|
153
|
+
* - Books
|
|
154
|
+
* example: "Sports"
|
|
155
|
+
* stock:
|
|
156
|
+
* type: integer
|
|
157
|
+
* example: 70
|
|
158
|
+
* responses:
|
|
159
|
+
* 200:
|
|
160
|
+
* description: Product updated
|
|
161
|
+
* 404:
|
|
162
|
+
* description: Product not found
|
|
163
|
+
*/
|
|
164
|
+
router.put(
|
|
165
|
+
"/:id",
|
|
166
|
+
asyncHandler(async (req: Request, res: Response) => {
|
|
167
|
+
const product = await productController.update(req.params.id, req.body);
|
|
168
|
+
res.json(product);
|
|
169
|
+
})
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* @swagger
|
|
174
|
+
* /products/{id}:
|
|
175
|
+
* delete:
|
|
176
|
+
* summary: Delete a product
|
|
177
|
+
* parameters:
|
|
178
|
+
* - name: id
|
|
179
|
+
* in: path
|
|
180
|
+
* required: true
|
|
181
|
+
* description: The ID of the product to delete
|
|
182
|
+
* schema:
|
|
183
|
+
* type: integer
|
|
184
|
+
* responses:
|
|
185
|
+
* 204:
|
|
186
|
+
* description: product deleted
|
|
187
|
+
* 400:
|
|
188
|
+
* description: invalid request
|
|
189
|
+
* 404:
|
|
190
|
+
* description: product not found
|
|
191
|
+
*/
|
|
192
|
+
router.delete(
|
|
193
|
+
"/:id",
|
|
194
|
+
asyncHandler(async (req: Request, res: Response) => {
|
|
195
|
+
const product = await productController.delete(req.params.id);
|
|
196
|
+
res.json(product);
|
|
197
|
+
})
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
export = router;
|