Skip to content

Commit 9e6cb90

Browse files
committed
refactor: streamline controller methods and remove try-catch blocks
1 parent 905d579 commit 9e6cb90

5 files changed

Lines changed: 258 additions & 181 deletions

File tree

.clinerules/03-ControllerPattern.md

Lines changed: 143 additions & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -180,69 +180,53 @@ async getList(
180180
},
181181
res: Response,
182182
) {
183-
try {
184-
const Model = this.app.getModel('ModelName');
185-
const { name, status } = req.appInfo.query;
186-
const { skip, limit, page } = req.appInfo.pagination;
187-
188-
const query: any = {};
189-
if (name) {
190-
query.name = new RegExp(name, 'i');
191-
}
192-
if (status) {
193-
query.status = status;
194-
}
195-
196-
const [items, total] = await Promise.all([
197-
Model.find(query).skip(skip).limit(limit),
198-
Model.countDocuments(query),
199-
]);
200-
201-
const publicItems = await Promise.all(
202-
items.map(async (item: any) => await item.getPublic())
203-
);
183+
const Model = this.app.getModel('ModelName');
184+
const { name, status } = req.appInfo.query;
185+
const { skip, limit, page } = req.appInfo.pagination;
204186

205-
return res.status(200).json({
206-
data: publicItems,
207-
total,
208-
page,
209-
limit,
210-
});
211-
} catch (error) {
212-
console.error('Error fetching items:', error);
213-
return res.status(500).json({
214-
message: req.appInfo?.i18n?.t('common.serverError') || 'Server error',
215-
data: null,
216-
});
187+
const query: any = {};
188+
if (name) {
189+
query.name = new RegExp(name, 'i');
190+
}
191+
if (status) {
192+
query.status = status;
217193
}
194+
195+
const [items, total] = await Promise.all([
196+
Model.find(query).skip(skip).limit(limit),
197+
Model.countDocuments(query),
198+
]);
199+
200+
const publicItems = await Promise.all(
201+
items.map(async (item: any) => await item.getPublic())
202+
);
203+
204+
return res.status(200).json({
205+
data: publicItems,
206+
total,
207+
page,
208+
limit,
209+
});
218210
}
219211
```
220212

221213
### GET by Slug Handler
222214
```typescript
223215
async getBySlug(req: FrameworkRequest, res: Response) {
224-
try {
225-
const Model = this.app.getModel('ModelName');
226-
const { slug } = req.params;
227-
228-
const item = await Model.findOne({ slug });
229-
if (!item) {
230-
return res.status(404).json({
231-
message: req.appInfo?.i18n?.t('model.notFound') || 'Item not found',
232-
data: null,
233-
});
234-
}
216+
const Model = this.app.getModel('ModelName');
217+
const { slug } = req.params;
235218

236-
return res.status(200).json({
237-
data: await item.getPublic(),
238-
});
239-
} catch (error) {
240-
console.error('Error fetching item:', error);
241-
return res.status(500).json({
242-
message: req.appInfo?.i18n?.t('common.serverError') || 'Server error',
219+
const item = await Model.findOne({ slug });
220+
if (!item) {
221+
return res.status(404).json({
222+
message: req.appInfo?.i18n?.t('model.notFound') || 'Item not found',
243223
data: null,
244224
});
245225
}
226+
227+
return res.status(200).json({
228+
data: await item.getPublic(),
229+
});
246230
}
247231
```
248232

@@ -260,70 +244,62 @@ async create(
260244
},
261245
res: Response,
262246
) {
263-
try {
264-
const Model = this.app.getModel('ModelName');
265-
const { name, description, image } = req.appInfo.request;
247+
const Model = this.app.getModel('ModelName');
248+
const { name, description, image } = req.appInfo.request;
249+
250+
// Validation
251+
const existingItem = await Model.findOne({ name: name[0] });
252+
if (existingItem) {
253+
return res.status(409).json({
254+
message: req.appInfo.i18n?.t('model.nameExistsMessage', { name: name[0] }) ||
255+
`Item with name "${name[0]}" already exists`,
256+
errors: {
257+
name: req.appInfo.i18n?.t('model.nameExists') || 'Name already exists',
258+
},
259+
data: null,
260+
});
261+
}
266262

267-
// Validation
268-
const existingItem = await Model.findOne({ name: name[0] });
269-
if (existingItem) {
270-
return res.status(409).json({
271-
message: req.appInfo.i18n?.t('model.nameExistsMessage', { name: name[0] }) ||
272-
`Item with name "${name[0]}" already exists`,
263+
// Handle file upload if needed
264+
let imageId = null;
265+
if (image?.[0]) {
266+
const FileModel = this.app.getModel('File');
267+
268+
if (!image[0].mimetype?.includes('image')) {
269+
return res.status(400).json({
273270
errors: {
274-
name: req.appInfo.i18n?.t('model.nameExists') || 'Name already exists',
271+
image: req.appInfo.i18n?.t('validation.fileNotImage') || 'File must be an image',
275272
},
276273
data: null,
277274
});
278275
}
279276

280-
// Handle file upload if needed
281-
let imageId = null;
282-
if (image?.[0]) {
283-
const FileModel = this.app.getModel('File');
284-
285-
if (!image[0].mimetype?.includes('image')) {
286-
return res.status(400).json({
287-
errors: {
288-
image: req.appInfo.i18n?.t('validation.fileNotImage') || 'File must be an image',
289-
},
290-
data: null,
291-
});
292-
}
293-
294-
const fileMongo = await FileModel.uploadFile(
295-
image[0].filepath,
296-
image[0].originalFilename,
297-
image[0].mimetype,
298-
'folder-name',
299-
);
300-
301-
if (!fileMongo) {
302-
return res.status(500).json({
303-
message: req.appInfo.i18n?.t('common.fileUploadFailed') || 'File upload failed',
304-
data: null,
305-
});
306-
}
307-
308-
imageId = fileMongo._id;
309-
}
277+
const fileMongo = await FileModel.uploadFile(
278+
image[0].filepath,
279+
image[0].originalFilename,
280+
image[0].mimetype,
281+
'folder-name',
282+
);
310283

311-
const newItem = await Model.create({
312-
name: name[0],
313-
description: description?.[0],
314-
image: imageId,
315-
});
284+
if (!fileMongo) {
285+
return res.status(500).json({
286+
message: req.appInfo.i18n?.t('common.fileUploadFailed') || 'File upload failed',
287+
data: null,
288+
});
289+
}
316290

317-
return res.status(201).json({
318-
data: await newItem.getPublic(),
319-
});
320-
} catch (error) {
321-
console.error('Error creating item:', error);
322-
return res.status(500).json({
323-
message: req.appInfo?.i18n?.t('common.serverError') || 'Server error',
324-
data: null,
325-
});
291+
imageId = fileMongo._id;
326292
}
293+
294+
const newItem = await Model.create({
295+
name: name[0],
296+
description: description?.[0],
297+
image: imageId,
298+
});
299+
300+
return res.status(201).json({
301+
data: await newItem.getPublic(),
302+
});
327303
}
328304
```
329305

@@ -341,98 +317,82 @@ async update(
341317
},
342318
res: Response,
343319
) {
344-
try {
345-
const Model = this.app.getModel('ModelName');
346-
const { slug } = req.params;
347-
const { name, description, image } = req.appInfo.request;
348-
349-
const item = await Model.findOne({ slug });
350-
if (!item) {
351-
return res.status(404).json({
352-
message: req.appInfo?.i18n?.t('model.notFound') || 'Item not found',
353-
data: null,
354-
});
355-
}
320+
const Model = this.app.getModel('ModelName');
321+
const { slug } = req.params;
322+
const { name, description, image } = req.appInfo.request;
323+
324+
const item = await Model.findOne({ slug });
325+
if (!item) {
326+
return res.status(404).json({
327+
message: req.appInfo?.i18n?.t('model.notFound') || 'Item not found',
328+
data: null,
329+
});
330+
}
356331

357-
// Check for duplicate name if updating
358-
if (name?.[0] && name[0] !== item.name) {
359-
const existingItem = await Model.findOne({
360-
name: name[0],
361-
slug: { $ne: slug },
362-
});
332+
// Check for duplicate name if updating
333+
if (name?.[0] && name[0] !== item.name) {
334+
const existingItem = await Model.findOne({
335+
name: name[0],
336+
slug: { $ne: slug },
337+
});
363338

364-
if (existingItem) {
365-
return res.status(409).json({
366-
message: req.appInfo.i18n?.t('model.nameExistsMessage', { name: name[0] }) ||
367-
`Item with name "${name[0]}" already exists`,
368-
errors: {
369-
name: req.appInfo.i18n?.t('model.nameExists') || 'Name already exists',
370-
},
371-
data: null,
372-
});
373-
}
339+
if (existingItem) {
340+
return res.status(409).json({
341+
message: req.appInfo.i18n?.t('model.nameExistsMessage', { name: name[0] }) ||
342+
`Item with name "${name[0]}" already exists`,
343+
errors: {
344+
name: req.appInfo.i18n?.t('model.nameExists') || 'Name already exists',
345+
},
346+
data: null,
347+
});
374348
}
349+
}
375350

376-
// Update fields
377-
const updateData: any = {};
378-
if (name?.[0]) {
379-
updateData.name = name[0];
380-
}
381-
if (description?.[0]) {
382-
updateData.description = description[0];
383-
}
351+
// Update fields
352+
const updateData: any = {};
353+
if (name?.[0]) {
354+
updateData.name = name[0];
355+
}
356+
if (description?.[0]) {
357+
updateData.description = description[0];
358+
}
384359

385-
// Handle image upload if provided
386-
if (image?.[0]) {
387-
// ... file upload logic similar to create
388-
}
360+
// Handle image upload if provided
361+
if (image?.[0]) {
362+
// ... file upload logic similar to create
363+
}
389364

390-
const updatedItem = await Model.findOneAndUpdate(
391-
{ slug },
392-
updateData,
393-
{ new: true }
394-
);
365+
const updatedItem = await Model.findOneAndUpdate(
366+
{ slug },
367+
updateData,
368+
{ new: true }
369+
);
395370

396-
return res.status(200).json({
397-
data: await updatedItem.getPublic(),
398-
});
399-
} catch (error) {
400-
console.error('Error updating item:', error);
401-
return res.status(500).json({
402-
message: req.appInfo?.i18n?.t('common.serverError') || 'Server error',
403-
data: null,
404-
});
405-
}
371+
return res.status(200).json({
372+
data: await updatedItem.getPublic(),
373+
});
406374
}
407375
```
408376

409377
### DELETE Handler
410378
```typescript
411379
async delete(req: FrameworkRequest, res: Response) {
412-
try {
413-
const Model = this.app.getModel('ModelName');
414-
const { slug } = req.params;
415-
416-
const item = await Model.findOne({ slug });
417-
if (!item) {
418-
return res.status(404).json({
419-
message: req.appInfo?.i18n?.t('model.notFound') || 'Item not found',
420-
data: null,
421-
});
422-
}
423-
424-
await Model.findOneAndDelete({ slug });
380+
const Model = this.app.getModel('ModelName');
381+
const { slug } = req.params;
425382

426-
return res.status(200).json({
427-
data: null,
428-
});
429-
} catch (error) {
430-
console.error('Error deleting item:', error);
431-
return res.status(500).json({
432-
message: req.appInfo?.i18n?.t('common.serverError') || 'Server error',
383+
const item = await Model.findOne({ slug });
384+
if (!item) {
385+
return res.status(404).json({
386+
message: req.appInfo?.i18n?.t('model.notFound') || 'Item not found',
433387
data: null,
434388
});
435389
}
390+
391+
await Model.findOneAndDelete({ slug });
392+
393+
return res.status(200).json({
394+
data: null,
395+
});
436396
}
437397
```
438398

@@ -444,7 +404,9 @@ async delete(req: FrameworkRequest, res: Response) {
444404
- Include internationalization support
445405

446406
### 2. Error Handling
447-
- Always wrap handlers in try-catch blocks
407+
- Framework handles errors automatically (see `.clinerules/07-ErrorHandling.md`)
408+
- Do NOT wrap main handler logic in try-catch blocks
409+
- Only use try-catch for specific non-critical operations (external APIs, logging, etc.)
448410
- Use appropriate HTTP status codes
449411
- Provide meaningful error messages
450412
- Use field-specific errors in the `errors` object

0 commit comments

Comments
 (0)