📖 What You’ll Learn:
-
What
async/awaitis and why it’s better than.then()/.catch() -
How to properly validate user input using
express-validator -
How to use Mongoose models to structure user data
-
How to return consistent error responses using
next()andtry/catch
🧱 Final File Structure (Reminder):
src/
│
├── models/
│ └── User.ts
├── controllers/
│ └── UserController.ts
├── routes/
│ └── UserRouter.ts
├── validators/
│ └── UserValidator.ts
🧠 Understanding async/await and try/catch
🔹 What is async/await?
-
asyncfunctions always return a Promise. -
awaitis used insideasyncfunctions to wait for the Promise to resolve. -
It makes asynchronous code look like synchronous code.
🔹 Why use async/await over .then().catch()?
.then().catch() |
async/await + try/catch |
|---|---|
| Nested callbacks can get messy | Cleaner and more readable |
| Error handling gets hard to trace | Centralized error handling with try/catch |
| Harder to debug | Easier to debug and maintain |
✅ Final Updated Code with Explanation
🗂️ controllers/UserController.ts
import { validationResult } from ‘express-validator’;
import User from ‘../models/User’;
export class UserController {
static async signUp(req, res, next) {
// Validate incoming data
const errors = validationResult(req);
if (!errors.isEmpty()) {
return next(new Error(errors.array()[0].msg));
}
// Destructure request body
const { email, password, username } = req.body;
// Prepare data
const userData = {
email,
password,
username
};
try {
// Wait for Mongoose to save the user
const user = await new User(userData).save();
// Send the saved user as response
res.status(201).json(user);
} catch (err) {
// Pass error to error-handling middleware
next(err);
}
}
}
🔍 Detailed Explanation for Beginners
| Line | Explanation |
|---|---|
async signUp(req, ...) |
Makes the function return a Promise so we can use await inside it |
validationResult(req) |
Gathers validation errors from express-validator |
if (!errors.isEmpty()) |
If there are validation errors, we send the first error back using next() |
await new User(data).save() |
Saves the user to MongoDB, but waits until it’s actually completed |
try { ... } catch (e) |
Catches any errors (like DB issues) and forwards them to error middleware |
📬 Testing in Postman
-
URL:
http://localhost:5000/api/user/signup -
Method:
POST -
Body Type:
x-www-form-urlencoded
| Key | Value |
|---|---|
| [email protected] | |
| password | testPassword123 |
| username | testuser |
✅ Sample Success Response
{
“_id”: “684edfa123abc671f7dfcc11”,
“email”: “[email protected]”,
“username”: “testuser”,
“password”: “testPassword123”,
“created_at”: “2025-06-28T12:00:00Z”,
“updated_at”: “2025-06-28T12:00:00Z”,
“__v”: 0
}
❌ Sample Error Responses
🔸 Missing Field
{
“message”: “Email is Required”,
“status_code”: 500
}
🔸 Duplicate Email
{
“message”: “User Already Exist”,
“status_code”: 500
}
🧠 Key Takeaways
-
Always validate incoming data using a middleware (like
express-validator). -
Use
async/await+try/catchfor cleaner, more readable code. -
Use
next()to forward errors to a centralized error handler. -
Structure your project using MVC pattern: Models, Routes, Controllers, Validators.