diff --git a/docs/basic-usage.md b/docs/basic-usage.md index 637c41e..670c1d7 100644 --- a/docs/basic-usage.md +++ b/docs/basic-usage.md @@ -131,6 +131,41 @@ La API proporciona los siguientes endpoints principales: - `PUT /api/heroes/:id`: Actualiza un héroe existente - `DELETE /api/heroes/:id`: Elimina un héroe por su ID +#### Eliminar un héroe + +- **Endpoint**: `DELETE /api/heroes/:id` +- **Descripción**: Elimina un héroe específico de la base de datos (solo para casos justificados) +- **Parámetros de ruta**: + - `id`: ID numérico del héroe +- **Parámetros de consulta**: + - `confirm`: Booleano (true/false) que confirma explícitamente la intención de eliminar +- **Respuesta exitosa** (código 200): + ```json + { + "success": true, + "message": "Hero Superman has been deleted" + } + ``` +- **Respuestas de error**: + - Sin confirmación (código 400): + ```json + { + "error": "Confirmation is required to delete a hero" + } + ``` + - Héroe no encontrado (código 404): + ```json + { + "error": "Hero with ID 999 not found" + } + ``` + - Error del servidor (código 500): + ```json + { + "error": "An unexpected error occurred while deleting the hero" + } + ``` + ## Ejemplos de Uso ### Obtener todos los héroes @@ -177,6 +212,12 @@ curl http://localhost:3000/api/heroes?name=man&page=1&limit=3 curl http://localhost:3000/api/heroes/1 ``` +### Eliminar un héroe (con confirmación) + +```bash +curl -X DELETE http://localhost:3000/api/heroes/1?confirm=true +``` + ## Próximos Pasos Para desarrollar en entornos más avanzados, consulta: diff --git a/heroes.http b/heroes.http index 9714d1d..ea9692d 100644 --- a/heroes.http +++ b/heroes.http @@ -71,4 +71,13 @@ Content-Type: {{contentType}} "alterEgo": "Spider-Man", "powers": ["Wall-Crawling", "Spider-Sense", "Super Strength"], "team": "Avengers" -} \ No newline at end of file +} + +### Delete hero without confirmation (will fail) +DELETE {{baseUrl}}/heroes/1 HTTP/1.1 + +### Delete hero with confirmation +DELETE {{baseUrl}}/heroes/1?confirm=true HTTP/1.1 + +### Delete non-existent hero (will fail) +DELETE {{baseUrl}}/heroes/999?confirm=true HTTP/1.1 \ No newline at end of file diff --git a/src/controllers/hero.controller.ts b/src/controllers/hero.controller.ts index 721a7cb..8a3d8b7 100644 --- a/src/controllers/hero.controller.ts +++ b/src/controllers/hero.controller.ts @@ -141,4 +141,44 @@ export class HeroController { next(error); } } + + /** + * Delete a hero by ID + * @route DELETE /api/heroes/:id + * @param {number} id - Hero ID + * @query {boolean} confirm - Confirmation flag to ensure deletion is intentional + * @returns {Object} Success message or error message + */ + async deleteHero(req: Request, res: Response, next: NextFunction): Promise { + try { + const id = Number(req.params.id); + const confirm = req.query.confirm === 'true'; + + if (isNaN(id)) { + res.status(400).json({ error: 'Invalid hero ID. ID must be a number.' }); + return; + } + + const result = await this.heroService.deleteHero(id, confirm); + + if (!result.success) { + // Determine appropriate status code based on error + if (result.error === 'Confirmation is required to delete a hero') { + res.status(400).json({ error: result.error }); + } else if (result.error?.includes('not found')) { + res.status(404).json({ error: result.error }); + } else { + res.status(500).json({ error: result.error }); + } + return; + } + + res.status(200).json({ + success: true, + message: result.message, + }); + } catch (error) { + next(error); + } + } } diff --git a/src/routes/hero.routes.ts b/src/routes/hero.routes.ts index 833ca6e..a92ea6f 100644 --- a/src/routes/hero.routes.ts +++ b/src/routes/hero.routes.ts @@ -8,5 +8,6 @@ const heroController = new HeroController(); router.get('/', (req, res, next) => heroController.getHeroes(req, res, next)); router.get('/:id', (req, res, next) => heroController.getHeroById(req, res, next)); router.post('/', (req, res, next) => heroController.createHero(req, res, next)); +router.delete('/:id', (req, res, next) => heroController.deleteHero(req, res, next)); export default router; diff --git a/src/services/hero.service.ts b/src/services/hero.service.ts index 6d83686..1791dc2 100644 --- a/src/services/hero.service.ts +++ b/src/services/hero.service.ts @@ -26,6 +26,13 @@ export interface CreateHeroResult { error?: string; } +// Define interface for hero deletion result +export interface DeleteHeroResult { + success: boolean; + message?: string; + error?: string; +} + export class HeroService { /** * Get heroes from the database with filtering and pagination @@ -146,4 +153,48 @@ export class HeroService { }; } } + + /** + * Delete a hero from the database + * @param id Hero id to delete + * @param confirm Confirmation flag to ensure deletion is intentional + * @returns Promise resolving to delete result with success flag and message or error + */ + async deleteHero(id: number, confirm: boolean): Promise { + try { + // Check if confirmation is provided + if (!confirm) { + return { + success: false, + error: 'Confirmation is required to delete a hero', + }; + } + + // Check if hero exists + const hero = await HeroModel.findOne({ id }); + if (!hero) { + return { + success: false, + error: `Hero with ID ${id} not found`, + }; + } + + // Delete the hero + await HeroModel.deleteOne({ id }); + + // Log the deletion for audit purposes + console.log(`Hero deleted: ${hero.name} (ID: ${id}) at ${new Date().toISOString()}`); + + return { + success: true, + message: `Hero ${hero.name} has been deleted`, + }; + } catch (error) { + console.error(`Error deleting hero with id ${id}:`, error); + return { + success: false, + error: 'An unexpected error occurred while deleting the hero', + }; + } + } }