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