
Backend API RESTful Express.js
Backend prêt pour la production avec architecture MVC modulaire et pipelines d'agrégation MongoDB.
Problème et solution
Construire un socle technique robuste doté d'une gestion centralisée des erreurs et de tests automatisés.
Fonctionnalités
- Authentification JWT avec renouvellement des refresh tokens
- Middleware d'autorisation basé sur les rôles
- Optimisation des requêtes d'agrégation MongoDB
- Validation stricte des données entrantes
- Tests d'intégration avec Jest et Supertest
Stack technique
| Technologie | Version | Objectif | Pourquoi ce choix |
|---|---|---|---|
| Node.js | — | JavaScript runtime | Non-blocking I/O, large ecosystem |
| Express.js | 4.19.2 | HTTP framework | Minimal, flexible, well-documented |
| TypeScript | 5.5.4 | Type safety | Compile-time error catching, IDE support |
| MongoDB | — | Document database | Flexible schema, JSON-native, horizontal scaling |
| Mongoose | 8.5.3 | MongoDB ODM | Schema validation, middleware, query building |
| JWT (jsonwebtoken) | 9.0.2 | Authentication tokens | Stateless auth, industry standard |
| bcrypt | 5.1.1 | Password hashing | Adaptive hashing, salt rounds |
| Cloudinary | 2.4.0 | Image hosting/CDN | Managed service, CDN, image transformations |
| Multer | 1.4.5-lts.1 | File upload handling | Express-integrated, simple API |
Architecture
Application Layers
- Express.js middleware pipeline (CORS, JSON parsing, JWT auth)
- Domain-based modular structure (users, adminUser, restaurant, orders)
- Controllers with direct Mongoose access (no service layer abstraction)
- Global error handler middleware with status code mapping
Infrastructure
- MongoDB via Mongoose 8.5.3 for document storage
- Cloudinary v2 for menu item image hosting and CDN
- Multer for multipart file upload handling
- JWT (jsonwebtoken) for stateless authentication
Structure du projet
Points d'API
RMS API (port 3000)
| Méthode | Route | Objectif |
|---|---|---|
| GET | / | Health check / welcome |
| POST | /api/users/register | Register new user |
| POST | /api/users/login | Login user |
| POST | /api/admin/createAdmin | Create admin user |
| POST | /api/admin/adminlogin | Login admin |
| POST | /api/restaurant/createRestaurant | Register restaurant owner |
| POST | /api/restaurant/ownerLogin | Login restaurant owner |
| POST | /api/Menuitems/addItems | Create menu item with image |
| PUT | /api/Menuitems/:itemId | Update menu item |
| GET | /api/Menuitems/getAllItems | List all menu items |
| GET | /api/Menuitems/:itemId | Get single menu item |
| DELETE | /api/Menuitems/:itemId | Delete menu item |
| POST | /api/orders/createorder | Create order |
| POST | /api/orders/cancelorder/:orderId | Cancel order |
| GET | /api/orders/orderdetails/:orderId | Get order details |
Conception de la base de données
users
| Colonne | Type | Notes |
|---|---|---|
| _idPK | ObjectId | Auto-generated |
| name | String | Required |
| String | Required, unique | |
| password | String | bcrypt hashed |
| createdAt | Date | Auto (timestamps: true) |
| updatedAt | Date | Auto (timestamps: true) |
User accounts. Email is unique.
admins
| Colonne | Type | Notes |
|---|---|---|
| _idPK | ObjectId | Auto-generated |
| name | String | Required |
| String | Required, unique | |
| password | String | bcrypt hashed |
| userType | String | enum: ['admin', 'user', 'restOwner'] |
Admin accounts. Separate collection from users.
restaurants
| Colonne | Type | Notes |
|---|---|---|
| _idPK | ObjectId | Auto-generated |
| restaurantEmail | String | Required |
| restaurantPwd | String | bcrypt hashed |
| restaurantName | String | Required |
| restaurantAddress | String | Required |
| restaurantPhoneNo | Number | Required, unique |
Restaurant owner accounts.
menuitems
| Colonne | Type | Notes |
|---|---|---|
| _idPK | ObjectId | Auto-generated |
| restaurantId | ObjectId | No ref defined — .populate() won't work |
| itemName | String | Has typo: require instead of required |
| itemDescription | String | Has typo: require instead of required |
| itemPrice | Number | Has typo: require instead of required |
| itemImage | String | Cloudinary URL |
Menu items per restaurant. restaurantId lacks ref property — schema bug.
orders
| Colonne | Type | Notes |
|---|---|---|
| _idPK | ObjectId | Auto-generated |
| customerId | ObjectId | ref: User |
| restaurantId | ObjectId | ref: restaurant |
| menuId | ObjectId | ref: MenuItems |
| orderQuantity | Number | No validation for positive values |
| orderDate | Date | Default: Date.now |
| orderStatus | String | enum: ['in process', 'transit', 'cancelled', 'delivered'] |
| orderBill | Number | Client-supplied — security concern |
Orders are client-supplied bill amounts — no server-side price calculation.
One-to-Many: Users→Orders, Restaurants→MenuItems, Restaurants→Orders, MenuItems→Orders. All via ObjectId references. No many-to-many relationships. menuitems.restaurantId lacks ref property.
Décisions de conception clés
Modular Monolith Architecture
Décision : Single Express.js application with domain-based folder structure
Pourquoi : Appropriate for project scale (~15 endpoints, single deployment)
Avantages : Simple deployment, easy debugging, low operational overhead, clear domain ownership
Compromis : Cannot scale domains independently, all modules share process, no service layer for reuse
JWT for Authentication
Décision : Stateless JWT tokens with Authorization: Bearer header
Pourquoi : Standard for REST APIs, no session storage needed
Avantages : Stateless, no server-side session store, scales horizontally
Compromis : No server-side revocation, tokens valid until expiry even if user is deleted
No Service Layer
Décision : Business logic resides directly in controllers
Pourquoi : Simplicity for small project, fewer files to navigate
Avantages : Fast development, fewer abstractions
Compromis : Untestable business logic, code duplication across auth controllers, hard to reuse logic
Cloudinary for Image Storage
Décision : Menu item images uploaded to Cloudinary CDN
Pourquoi : Managed service avoids S3/MinIO setup, provides CDN and image transformations
Avantages : No infrastructure to manage, built-in CDN, free tier available
Compromis : Vendor lock-in, external dependency, cost at scale, latency for non-CDN regions
Client-Supplied Order Bill
Décision : orderBill is sent by the client, not calculated server-side
Pourquoi : Likely intentional simplification for MVP
Avantages : Simpler server logic
Compromis : Critical security vulnerability — clients can manipulate order amounts
No Request Validation Library
Décision : Manual if (!field) validation instead of Zod/Joi
Pourquoi : Simplicity, fewer dependencies
Avantages : No additional dependency, explicit control
Compromis : Inconsistent validation, no type inference from schemas, generic error messages
Tests
Ce qui est testé
Couverture manquante
- No test framework installed (no jest, mocha, vitest)
- No test files or test directories
- No unit tests for controllers or middleware
- No integration tests for API endpoints
- No authentication flow tests
- No database operation tests
Défis clés
- Développer un middleware performant pour la sécurité et le rate limiting
- Standardiser les réponses d'erreur sur l'ensemble de l'API
Apprentissages clés
- Architecture MVC modulaire avec TypeScript et Node.js
- Stratégies d'indexation avancées dans MongoDB