Middleware in Express: Keep Your Server Chill with Global Error Handling and Zod 😎

What’s Middleware?

When you're building APIs or web apps in Express.js, middleware is like that homie who handles all the important tasks before you even get to the fun part (your routes). 🚀 Whether it’s parsing JSON, checking if a user is logged in, or making sure the data you’re receiving is legit, middleware is the go-to!

So yeah, middleware are those background tasks that run before your actual route logic kicks in. Think of it like getting your car checked before hitting the road 🛣️. Let’s dive into why it’s important and how you can use it to keep your app fresh.


Why Global Error Handling? 🤔

Imagine this: you're cruising on your app, making requests, living life, and suddenly... BOOM, a 500 Internal Server Error smacks you right in the face because of some weird request. 😱 Like, no one wants that, right?

That’s why global error handling is your best friend. It’s there to catch all the errors your app throws at it—whether it’s bad data or weird bugs—and sends a clean response instead of crashing your server like a noob. ⚡

Let’s make sure your app never crashes from a bad request with some super chill error-handling middleware.

How to Handle Errors Like a Boss 💼

const express = require('express');
const app = express();

// Middleware to parse incoming JSON data (it’s like your bouncer at the door 🕴️)
app.use(express.json());

// Global Error Handler for bad JSON and other errors 🔥
app.use((err, req, res, next) => {
    if (err instanceof SyntaxError) {
        return res.status(400).json({ msg: 'Bruh, that’s invalid JSON! 🤦‍♂️' });
    }
    next(err); // Pass the error to the next handler if it’s not a SyntaxError
});

// Sample route – register a new user (don’t forget your fields!)
app.post('/user', (req, res) => {
    const { name, age } = req.body;
    if (!name || !age) {
        throw new Error('Missing fields, bro! 😡');
    }
    res.send(`Yo, ${name}, you’re ${age} years old! 👑`);
});

// Catch other errors (server fails? No worries, we got this!) 😎
app.use((err, req, res, next) => {
    res.status(500).json({ msg: 'Something went wrong on the server 💣. Let’s fix it!' });
});

app.listen(3000, () => {
    console.log('Server is up and running on port 3000 🚀');
});

Now, with this setup:

  • If you send bad JSON, the server won't crash! Instead, you’ll get a neat response with the error message: Invalid JSON syntax.

  • If something’s wrong with the request (like missing a field), you’ll see a Missing fields, bro! message.


Zod to the Rescue! 🦸‍♂️

Okay, we’ve got our middleware and error handling down. But what about making sure that the data coming in is legit? That’s where Zod comes in like a superhero. 🦸‍♀️ Zod is a validation library that checks if the data your app receives is exactly what you want, like a bouncer checking IDs before letting people into the club. 😎

Let’s use Zod to make sure only valid user data gets processed, and anything else gets sent to the curb 🚷.

How Zod Saves the Day

We’re going to create a route where users can register with their name, email, and age. But, we need to make sure they’re not sending any garbage. Zod is our gatekeeper! 🏰

const express = require('express');
const zod = require('zod');
const app = express();

// We need to parse incoming JSON data (again, don’t skip this step! 🛑)
app.use(express.json());

// Define the Zod schema to validate user data (super easy!)
const userSchema = zod.object({
    name: zod.string().min(1, "Name is required! 🤬"),  // Name can’t be empty, bro!
    email: zod.string().email("Yo, that's not an email 🤔"),  // Email needs to be valid!
    age: zod.number().int().positive("Age must be a positive number, fam! 💪"),  // Age? Positive only, please!
});

// Register route – we check if the user input is good with Zod 💥
app.post('/register', (req, res) => {
    const { name, email, age } = req.body;

    // Validate with Zod!
    const result = userSchema.safeParse({ name, email, age });

    if (!result.success) {
        return res.status(400).json({
            msg: 'Something went wrong with your input 🤷‍♂️',
            errors: result.error.errors,  // Zod gives us detailed errors so we know what went wrong!
        });
    }

    // If everything checks out, we send a success message 🎉
    res.send(`Yo, ${name}, you’re all set! Welcome to the club! 🎉`);
});

// Global error handler (just in case, ya know 🤞)
app.use((err, req, res, next) => {
    if (err instanceof SyntaxError) {
        return res.status(400).json({ msg: 'Bro, you sent invalid JSON! 🥲' });
    }
    res.status(500).json({ msg: 'Something went down on the server. Let’s fix it! 🛠️' });
});

app.listen(3000, () => {
    console.log('Server is up and running, let’s get this bread 🍞 on port 3000!');
});

How Zod Works Like a Charm 💎

  • Define the Schema: We define the expected data structure (name, email, age).

  • Validation: Zod checks if the user’s data is valid. If not, it gives detailed error messages.

  • Error Handling: If something goes wrong, you get a 400 Bad Request and a friendly error message.

Example Request:

{
    "name": "John Doe",
    "email": "john.doe@example.com",
    "age": 25
}

Everything’s fine? 🎉 You’ll get:

Yo, John Doe, you’re all set! Welcome to the club! 🎉

But if you send a bad email, like john.doe@com:

{
    "msg": "Something went wrong with your input 🤷‍♂️",
    "errors": [
        {
            "message": "Yo, that's not an email 🤔",
            "path": ["email"],
            "code": "invalid_type"
        }
    ]
}

Conclusion: Middleware + Global Error Handling + Zod = 💯

Bro, now you know how to keep your Express app smooth, robust, and resilient using:

  1. Middleware: Handling all the background stuff (like JSON parsing and logging).

  2. Global Error Handling: Catching those annoying errors to make sure your server doesn’t crash like a rookie.

  3. Zod: Validating incoming data to make sure everything checks out before going through.

By combining all three, your server’s ready to handle anything that comes its way—like a pro. 🎯


I hope you enjoyed the ride! 🚗💨 Stay chill, keep coding, and your apps will be unstoppable! 💪 Let me know what you think—hit me with a comment below if you’ve got questions! 👇

Did you find this article valuable?

Support Abhishek Raut by becoming a sponsor. Any amount is appreciated!