DEV Community

Cover image for Make your Node.js APIs bulletproof using TypeScript Decorators 🛡️
João Neto
João Neto

Posted on

Make your Node.js APIs bulletproof using TypeScript Decorators 🛡️

In the world of microservices and distributed systems, network failures are not a matter of "if", but "when". A single failing service can hang your entire application, consuming resources until it crashes.

To prevent this, the Circuit Breaker pattern is essential. But let's be honest: implementing it often leads to messy code, with try/catch blocks wrapping every single API call.

Today, I want to show you how to solve this elegantly using surge-kit, a lightweight, zero-dependency library I built for Node.js.

With the release of v0.5.0, we can now use TypeScript Decorators to handle resilience declaratively.

The Problem: "Wrapper Hell" 😫

Usually, protecting a method looks like this:

// The "Old Way"
async getUser(id: string) {
  try {
    // Manual wrapping... repetitive and verbose
    return await circuitBreaker.fire(async () => {
       return await axios.get(`/users/${id}`);
    });
  } catch (error) {
    // Manual fallback logic...
    return null;
  }
}
Enter fullscreen mode Exit fullscreen mode

It works, but it hurts readability.

The Solution: Decorators ✨
With surge-kit, we can strip away all that boilerplate.

  1. Installation First, install the package:
npm install surge-kit
Enter fullscreen mode Exit fullscreen mode

(Note: Make sure you have "experimentalDecorators": true in your tsconfig.json)

2. Global Setup (Singleton)

You probably want to share the same Circuit Breaker configuration across your app. You can set a default instance once (e.g., in your main.ts or app.ts):

import { Relay } from 'surge-kit';

// Configure your breaker
const globalRelay = new Relay({
  failureThreshold: 3,      // Open after 3 failures
  coolDownPeriod: 10000,    // Wait 10s before retrying
  useExponentialBackoff: true // Smart cooldown! 🧠
});

// Set it as the default
Relay.setDefault(globalRelay);
Enter fullscreen mode Exit fullscreen mode

3. Protecting Your Methods

Now, you can simply decorate your methods. No more wrappers!

import { UseRelay, Fallback } from 'surge-kit';

class UserService {

  @Fallback((err) => {
     console.warn(`Service failed: ${err.message}`);
     return { id: 0, name: "Guest User" }; // Return cached or default data
  })
  @UseRelay() // Automatically uses the default circuit breaker
  async getUser(id: string) {
    // Just your clean business logic!
    const { data } = await axios.get(`https://api.example.com/users/${id}`);
    return data;
  }
}
Enter fullscreen mode Exit fullscreen mode

If the API fails (or times out), surge-kit counts the failure. If the threshold is reached, the circuit opens, and subsequent calls fail fast (or use the fallback) without hitting the struggling API.

Why surge-kit?

I built this because existing solutions felt too heavy for simple use cases.

⚡ Zero Dependencies: It’s tiny and won’t bloat your node_modules.

🛡️ Production Ready: Includes Exponential Backoff (cooldown increases if the service stays down) and execution Timeouts.

🔍 Observability: It exposes metrics and emits events (OPEN, CLOSE, HALF_OPEN) so you can plug it into your logging system.

Try it out!

The project is Open Source and I'm actively looking for feedback and contributors.

📦 NPM: npmjs.com/package/surge-kit

🐙 GitHub: github.com/Dev-Etto/surge-kit

If you found this useful, leave a ⭐ on the repo! It helps a lot.

Happy coding! 🚀

Top comments (0)