When Your TypeScript Service Meets Chaos
\nImagine: your TypeScript application works perfectly — tests pass, deployment goes smoothly, users are happy. But then 3 AM strikes, and the Redis cluster decides to "take a nap." Or the CDN starts returning 503 errors. Or, even funnier, a network packet gets lost somewhere between continents.
\nAt that moment, your neat TypeScript code, written with care, might behave like a frightened cat. Or like a superhero. It all depends on whether you've trained it to face chaos head-on.
\nChaos engineering is not about breaking production. It's about learning to break correctly. And TypeScript, with its strict typing and powerful abstractions, is an excellent training ground for such exercises.
\n\nWhat Chaos Engineering Really Is
\nChaos engineering is the discipline of experimenting on a distributed system to uncover its weaknesses before users do. In the context of TypeScript applications, this means:
\n- \n
- Systematic fault injection — disabling services, delays, network errors \n
- Observing behavior — how your code reacts to surprises \n
- Automating experiments — to run them regularly \n
- Improving architecture — based on the data obtained \n
The main rule: you should not learn about a problem from an angry user. Better to let your automated "destroyer" discover it in a controlled environment.
\n\nWhy TypeScript is Ideal for Chaos Engineering
\nTypeScript is not just a superset of JavaScript. It's an opportunity to write code that is predictable even in chaos. Here's why:
\n- \n
- Strict typing — you know exactly what data comes in and goes out. But what if undefined arrives instead of a number? Chaos tests will check that. \n
- Asynchrony — Promise, async/await, Observable — all of these can "break" in interesting ways during network issues. \n
- Ecosystem — Jest, Mocha, Playwright — ready-made tools for integrating chaos scenarios. \n
Practical Example: Injecting Chaos into an Express Application
\nLet's imagine we have a simple Express application in TypeScript that calls an external API to get weather data. We want to test how it behaves if that API becomes unavailable.
\n\nStep 1: Write a Regular Service
\n// weather.service.ts\ninterface WeatherResponse {\n temperature: number;\n humidity: number;\n condition: string;\n}\n\nclass WeatherService {\n async getWeather(city: string): Promise<WeatherResponse> {\n const response = await fetch(`https://api.weather.com/v1/${city}`);\n \n if (!response.ok) {\n throw new Error(`Weather API error: ${response.status}`);\n }\n \n return response.json() as Promise<WeatherResponse>;\n }\n}\n\nexport const weatherService = new WeatherService();\n\nStep 2: Add a Controller with Protection
\n// weather.controller.ts\nimport { Request, Response } from 'express';\nimport { weatherService } from './weather.service';\n\nclass WeatherController {\n async getWeatherHandler(req: Request, res: Response) {\n const { city } = req.params;\n \n try {\n const weather = await weatherService.getWeather(city);\n res.json(weather);\n } catch (error) {\n // Log the error\n console.error(`Failed to fetch weather for ${city}:`, error);\n \n // Return a fallback response\n res.status(503).json({\n error: 'Service temporarily unavailable',\n fallback: {\n tempe