Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions samples/api-degradation-scenarios/.devproxy/devproxyrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/rc.schema.json",
"plugins": [
{
"name": "RetryAfterPlugin",
"enabled": true,
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll"
},
{
"name": "LatencyPlugin",
"enabled": true,
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
"configSection": "latencyPlugin"
},
{
"name": "RateLimitingPlugin",
"enabled": true,
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
"configSection": "rateLimitingPlugin"
},
{
"name": "GenericRandomErrorPlugin",
"enabled": true,
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
"configSection": "genericRandomErrorPlugin"
},
{
"name": "MockResponsePlugin",
"enabled": true,
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
"configSection": "mockResponsePlugin"
}
],
"urlsToWatch": [
"https://api.example.com/*"
],
"latencyPlugin": {
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/latencyplugin.schema.json",
"minMs": 3000,
"maxMs": 5000
},
"rateLimitingPlugin": {
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/ratelimitingplugin.schema.json",
"costPerRequest": 1,
"rateLimit": 10
},
"genericRandomErrorPlugin": {
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/genericrandomerrorplugin.schema.json",
"errorsFile": "errors-503.json",
"rate": 30
},
"mockResponsePlugin": {
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/mockresponseplugin.schema.json",
"mocksFile": "mocks.json"
}
}
81 changes: 81 additions & 0 deletions samples/api-degradation-scenarios/.devproxy/errors-503.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/genericrandomerrorplugin.errorsfile.schema.json",
"errors": [
{
"request": {
"url": "https://api.example.com/*"
},
"responses": [
{
"statusCode": 503,
"headers": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Retry-After",
"value": "@dynamic"
},
{
"name": "Access-Control-Allow-Origin",
"value": "*"
}
],
"body": {
"error": {
"code": "ServiceUnavailable",
"message": "Service is temporarily unavailable. Please retry later."
}
}
},
{
"statusCode": 503,
"headers": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Retry-After",
"value": "@dynamic"
},
{
"name": "Access-Control-Allow-Origin",
"value": "*"
}
],
"body": {
"error": {
"code": "ServerBusy",
"message": "The server is currently busy. Please try again in a few moments."
}
}
},
{
"statusCode": 503,
"headers": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Retry-After",
"value": "@dynamic"
},
{
"name": "Access-Control-Allow-Origin",
"value": "*"
}
],
"body": {
"error": {
"code": "CapacityExceeded",
"message": "Server capacity exceeded. Please wait before retrying."
}
}
}
]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/rc.schema.json",
"plugins": [
{
"name": "RetryAfterPlugin",
"enabled": true,
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll"
},
{
"name": "GenericRandomErrorPlugin",
"enabled": true,
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
"configSection": "genericRandomErrorPlugin"
},
{
"name": "MockResponsePlugin",
"enabled": true,
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
"configSection": "mockResponsePlugin"
}
],
"urlsToWatch": [
"https://api.example.com/*"
],
"genericRandomErrorPlugin": {
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/genericrandomerrorplugin.schema.json",
"errorsFile": "errors-503.json",
"rate": 30
},
"mockResponsePlugin": {
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/mockresponseplugin.schema.json",
"mocksFile": "mocks.json"
}
}
27 changes: 27 additions & 0 deletions samples/api-degradation-scenarios/.devproxy/mocks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/mockresponseplugin.mocksfile.schema.json",
"mocks": [
{
"request": {
"url": "https://api.example.com/*"
},
"response": {
"statusCode": 200,
"headers": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Access-Control-Allow-Origin",
"value": "*"
}
],
"body": {
"status": "ok",
"message": "Request processed successfully"
}
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/rc.schema.json",
"plugins": [
{
"name": "RetryAfterPlugin",
"enabled": true,
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll"
},
{
"name": "RateLimitingPlugin",
"enabled": true,
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
"configSection": "rateLimitingPlugin"
},
{
"name": "MockResponsePlugin",
"enabled": true,
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
"configSection": "mockResponsePlugin"
}
],
"urlsToWatch": [
"https://api.example.com/*"
],
"rateLimitingPlugin": {
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/ratelimitingplugin.schema.json",
"costPerRequest": 1,
"rateLimit": 10
},
"mockResponsePlugin": {
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/mockresponseplugin.schema.json",
"mocksFile": "mocks.json"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/rc.schema.json",
"plugins": [
{
"name": "LatencyPlugin",
"enabled": true,
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
"configSection": "latencyPlugin"
},
{
"name": "MockResponsePlugin",
"enabled": true,
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
"configSection": "mockResponsePlugin"
}
],
"urlsToWatch": [
"https://api.example.com/*"
],
"latencyPlugin": {
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/latencyplugin.schema.json",
"minMs": 3000,
"maxMs": 5000
},
"mockResponsePlugin": {
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/mockresponseplugin.schema.json",
"mocksFile": "mocks.json"
}
}
132 changes: 132 additions & 0 deletions samples/api-degradation-scenarios/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Simulate API degradation scenarios

## Summary

This sample demonstrates how to simulate various API degradation scenarios to test how your application handles partial failures, intermittent errors, rate limiting, and slow responses. Use these configurations to build apps that gracefully degrade under stress and verify that your error handling and retry logic works before production.

![API Degradation Monitoring Dashboard](assets/screenshot.png)

## Compatibility

![Dev Proxy v2.0.0](https://aka.ms/devproxy/badge/v2.0.0)

## Contributors

- [Waldek Mastykarz](https://github.com/waldekmastykarz)

## Version history

Version|Date|Comments
-------|----|--------
1.0|January 18, 2026|Initial release

## Prerequisites

- [Node.js LTS](https://nodejs.org)

## Minimal path to awesome

- Clone this repository (or [download this solution as a .ZIP file](https://pnp.github.io/download-partial/?url=https://github.com/pnp/proxy-samples/tree/main/samples/api-degradation-scenarios) then unzip it)
- Start the sample app and Dev Proxy by running `npm start`
- In a web browser, navigate to `http://localhost:3000` and use the dashboard to test API degradation scenarios

### Using the monitoring dashboard

The included web app provides a real-time monitoring dashboard that shows:

- **Total Requests** - Number of requests made
- **Success Rate** - Percentage of successful requests
- **Average Response Time** - Average response time across all requests
- **Error counts** - Breakdown of 503 and 429 errors
- **Response Distribution** - Visual bar chart of response types

Use the dashboard buttons to:

- **Send Single Request** - Make one API request
- **Send Burst (10 requests)** - Make 10 concurrent requests to trigger rate limiting
- **Start Auto Requests** - Continuously send requests every second
- **Stop** - Stop auto requests
- **Clear Stats** - Reset all statistics

### Using Dev Proxy configurations directly

You can also run Dev Proxy with specific configurations:

### All degradation scenarios combined

This configuration combines all three degradation scenarios: intermittent 503 errors (30% of requests), rate limiting (10 requests per minute), and slow responses (3-5 seconds latency).

```bash
devproxy
```

### Intermittent 503 errors only

This configuration simulates random 503 Service Unavailable errors for 30% of requests.

```bash
devproxy --config-file .devproxy/intermittent-errors.devproxyrc.json
```

### Rate limiting only

This configuration simulates hitting rate limits with 429 Too Many Requests responses after 10 requests per minute.

```bash
devproxy --config-file .devproxy/rate-limiting.devproxyrc.json
```

### Slow responses only

This configuration adds random latency (3-5 seconds) to all responses.

```bash
devproxy --config-file .devproxy/slow-responses.devproxyrc.json
```

## Features

This sample demonstrates how to use Dev Proxy to simulate API degradation scenarios. Using this sample you can:

- Test your application's handling of intermittent 503 Service Unavailable errors
- Verify retry logic and exponential backoff implementation
- Test rate limit handling and proper use of Retry-After headers
- Measure application performance under slow network conditions
- Validate graceful degradation patterns in your application
- Demonstrate that your error handling works before deploying to production

### Configuration files

| File | Description |
|------|-------------|
| `.devproxy/devproxyrc.json` | Combined configuration with all degradation scenarios |
| `.devproxy/intermittent-errors.devproxyrc.json` | 503 errors at 30% failure rate |
| `.devproxy/rate-limiting.devproxyrc.json` | Rate limiting at 10 requests/minute |
| `.devproxy/slow-responses.devproxyrc.json` | Random latency between 3-5 seconds |
| `.devproxy/errors-503.json` | Error responses for the GenericRandomErrorPlugin |
| `.devproxy/mocks.json` | Mock responses for successful requests |
| `index.html` | Monitoring dashboard web app |
| `package.json` | Node.js configuration to run the sample |

### Plugins used

- **GenericRandomErrorPlugin** - Simulates random errors at a configurable rate
- **LatencyPlugin** - Adds random delays to responses
- **RateLimitingPlugin** - Simulates API rate limiting behavior
- **RetryAfterPlugin** - Validates that clients respect Retry-After headers

## Help

We do not support samples, but this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues.

You can try looking at [issues related to this sample](https://github.com/pnp/proxy-samples/issues?q=label%3A%22sample%3A%20api-degradation-scenarios%22) to see if anybody else is having the same issues.

If you encounter any issues using this sample, [create a new issue](https://github.com/pnp/proxy-samples/issues/new).

Finally, if you have an idea for improvement, [make a suggestion](https://github.com/pnp/proxy-samples/issues/new).

## Disclaimer

**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**

![](https://m365-visitor-stats.azurewebsites.net/SamplesGallery/pnp-devproxy-api-degradation-scenarios)
Loading