Skip to content

Commit d3bc4fd

Browse files
Sample: api-degradation-scenarios - Simulate partial API failures (#44)
* Add api-degradation-scenarios sample with Dev Proxy configurations Co-authored-by: waldekmastykarz <11164679+waldekmastykarz@users.noreply.github.com> * Add web app monitoring dashboard, update dates, author, and follow Dev Proxy best practices Co-authored-by: waldekmastykarz <11164679+waldekmastykarz@users.noreply.github.com> * Update dates to 2026-01-10 per copilot-instructions.md Co-authored-by: waldekmastykarz <11164679+waldekmastykarz@users.noreply.github.com> * Update screenshot to reflect current monitoring dashboard Co-authored-by: waldekmastykarz <11164679+waldekmastykarz@users.noreply.github.com> * Move config files to .devproxy folder and remove default property values Co-authored-by: waldekmastykarz <11164679+waldekmastykarz@users.noreply.github.com> * Address review feedback: fix PRESET flag, simplify devproxy commands, remove curl examples Co-authored-by: waldekmastykarz <11164679+waldekmastykarz@users.noreply.github.com> * Updates --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: waldekmastykarz <11164679+waldekmastykarz@users.noreply.github.com> Co-authored-by: waldekmastykarz <waldek@mastykarz.nl>
1 parent bec3eb5 commit d3bc4fd

File tree

11 files changed

+1014
-0
lines changed

11 files changed

+1014
-0
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
{
2+
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/rc.schema.json",
3+
"plugins": [
4+
{
5+
"name": "RetryAfterPlugin",
6+
"enabled": true,
7+
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll"
8+
},
9+
{
10+
"name": "LatencyPlugin",
11+
"enabled": true,
12+
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
13+
"configSection": "latencyPlugin"
14+
},
15+
{
16+
"name": "RateLimitingPlugin",
17+
"enabled": true,
18+
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
19+
"configSection": "rateLimitingPlugin"
20+
},
21+
{
22+
"name": "GenericRandomErrorPlugin",
23+
"enabled": true,
24+
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
25+
"configSection": "genericRandomErrorPlugin"
26+
},
27+
{
28+
"name": "MockResponsePlugin",
29+
"enabled": true,
30+
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
31+
"configSection": "mockResponsePlugin"
32+
}
33+
],
34+
"urlsToWatch": [
35+
"https://api.example.com/*"
36+
],
37+
"latencyPlugin": {
38+
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/latencyplugin.schema.json",
39+
"minMs": 3000,
40+
"maxMs": 5000
41+
},
42+
"rateLimitingPlugin": {
43+
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/ratelimitingplugin.schema.json",
44+
"costPerRequest": 1,
45+
"rateLimit": 10
46+
},
47+
"genericRandomErrorPlugin": {
48+
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/genericrandomerrorplugin.schema.json",
49+
"errorsFile": "errors-503.json",
50+
"rate": 30
51+
},
52+
"mockResponsePlugin": {
53+
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/mockresponseplugin.schema.json",
54+
"mocksFile": "mocks.json"
55+
}
56+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
{
2+
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/genericrandomerrorplugin.errorsfile.schema.json",
3+
"errors": [
4+
{
5+
"request": {
6+
"url": "https://api.example.com/*"
7+
},
8+
"responses": [
9+
{
10+
"statusCode": 503,
11+
"headers": [
12+
{
13+
"name": "Content-Type",
14+
"value": "application/json"
15+
},
16+
{
17+
"name": "Retry-After",
18+
"value": "@dynamic"
19+
},
20+
{
21+
"name": "Access-Control-Allow-Origin",
22+
"value": "*"
23+
}
24+
],
25+
"body": {
26+
"error": {
27+
"code": "ServiceUnavailable",
28+
"message": "Service is temporarily unavailable. Please retry later."
29+
}
30+
}
31+
},
32+
{
33+
"statusCode": 503,
34+
"headers": [
35+
{
36+
"name": "Content-Type",
37+
"value": "application/json"
38+
},
39+
{
40+
"name": "Retry-After",
41+
"value": "@dynamic"
42+
},
43+
{
44+
"name": "Access-Control-Allow-Origin",
45+
"value": "*"
46+
}
47+
],
48+
"body": {
49+
"error": {
50+
"code": "ServerBusy",
51+
"message": "The server is currently busy. Please try again in a few moments."
52+
}
53+
}
54+
},
55+
{
56+
"statusCode": 503,
57+
"headers": [
58+
{
59+
"name": "Content-Type",
60+
"value": "application/json"
61+
},
62+
{
63+
"name": "Retry-After",
64+
"value": "@dynamic"
65+
},
66+
{
67+
"name": "Access-Control-Allow-Origin",
68+
"value": "*"
69+
}
70+
],
71+
"body": {
72+
"error": {
73+
"code": "CapacityExceeded",
74+
"message": "Server capacity exceeded. Please wait before retrying."
75+
}
76+
}
77+
}
78+
]
79+
}
80+
]
81+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/rc.schema.json",
3+
"plugins": [
4+
{
5+
"name": "RetryAfterPlugin",
6+
"enabled": true,
7+
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll"
8+
},
9+
{
10+
"name": "GenericRandomErrorPlugin",
11+
"enabled": true,
12+
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
13+
"configSection": "genericRandomErrorPlugin"
14+
},
15+
{
16+
"name": "MockResponsePlugin",
17+
"enabled": true,
18+
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
19+
"configSection": "mockResponsePlugin"
20+
}
21+
],
22+
"urlsToWatch": [
23+
"https://api.example.com/*"
24+
],
25+
"genericRandomErrorPlugin": {
26+
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/genericrandomerrorplugin.schema.json",
27+
"errorsFile": "errors-503.json",
28+
"rate": 30
29+
},
30+
"mockResponsePlugin": {
31+
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/mockresponseplugin.schema.json",
32+
"mocksFile": "mocks.json"
33+
}
34+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/mockresponseplugin.mocksfile.schema.json",
3+
"mocks": [
4+
{
5+
"request": {
6+
"url": "https://api.example.com/*"
7+
},
8+
"response": {
9+
"statusCode": 200,
10+
"headers": [
11+
{
12+
"name": "Content-Type",
13+
"value": "application/json"
14+
},
15+
{
16+
"name": "Access-Control-Allow-Origin",
17+
"value": "*"
18+
}
19+
],
20+
"body": {
21+
"status": "ok",
22+
"message": "Request processed successfully"
23+
}
24+
}
25+
}
26+
]
27+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/rc.schema.json",
3+
"plugins": [
4+
{
5+
"name": "RetryAfterPlugin",
6+
"enabled": true,
7+
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll"
8+
},
9+
{
10+
"name": "RateLimitingPlugin",
11+
"enabled": true,
12+
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
13+
"configSection": "rateLimitingPlugin"
14+
},
15+
{
16+
"name": "MockResponsePlugin",
17+
"enabled": true,
18+
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
19+
"configSection": "mockResponsePlugin"
20+
}
21+
],
22+
"urlsToWatch": [
23+
"https://api.example.com/*"
24+
],
25+
"rateLimitingPlugin": {
26+
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/ratelimitingplugin.schema.json",
27+
"costPerRequest": 1,
28+
"rateLimit": 10
29+
},
30+
"mockResponsePlugin": {
31+
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/mockresponseplugin.schema.json",
32+
"mocksFile": "mocks.json"
33+
}
34+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/rc.schema.json",
3+
"plugins": [
4+
{
5+
"name": "LatencyPlugin",
6+
"enabled": true,
7+
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
8+
"configSection": "latencyPlugin"
9+
},
10+
{
11+
"name": "MockResponsePlugin",
12+
"enabled": true,
13+
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
14+
"configSection": "mockResponsePlugin"
15+
}
16+
],
17+
"urlsToWatch": [
18+
"https://api.example.com/*"
19+
],
20+
"latencyPlugin": {
21+
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/latencyplugin.schema.json",
22+
"minMs": 3000,
23+
"maxMs": 5000
24+
},
25+
"mockResponsePlugin": {
26+
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/mockresponseplugin.schema.json",
27+
"mocksFile": "mocks.json"
28+
}
29+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# Simulate API degradation scenarios
2+
3+
## Summary
4+
5+
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.
6+
7+
![API Degradation Monitoring Dashboard](assets/screenshot.png)
8+
9+
## Compatibility
10+
11+
![Dev Proxy v2.0.0](https://aka.ms/devproxy/badge/v2.0.0)
12+
13+
## Contributors
14+
15+
- [Waldek Mastykarz](https://github.com/waldekmastykarz)
16+
17+
## Version history
18+
19+
Version|Date|Comments
20+
-------|----|--------
21+
1.0|January 18, 2026|Initial release
22+
23+
## Prerequisites
24+
25+
- [Node.js LTS](https://nodejs.org)
26+
27+
## Minimal path to awesome
28+
29+
- 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)
30+
- Start the sample app and Dev Proxy by running `npm start`
31+
- In a web browser, navigate to `http://localhost:3000` and use the dashboard to test API degradation scenarios
32+
33+
### Using the monitoring dashboard
34+
35+
The included web app provides a real-time monitoring dashboard that shows:
36+
37+
- **Total Requests** - Number of requests made
38+
- **Success Rate** - Percentage of successful requests
39+
- **Average Response Time** - Average response time across all requests
40+
- **Error counts** - Breakdown of 503 and 429 errors
41+
- **Response Distribution** - Visual bar chart of response types
42+
43+
Use the dashboard buttons to:
44+
45+
- **Send Single Request** - Make one API request
46+
- **Send Burst (10 requests)** - Make 10 concurrent requests to trigger rate limiting
47+
- **Start Auto Requests** - Continuously send requests every second
48+
- **Stop** - Stop auto requests
49+
- **Clear Stats** - Reset all statistics
50+
51+
### Using Dev Proxy configurations directly
52+
53+
You can also run Dev Proxy with specific configurations:
54+
55+
### All degradation scenarios combined
56+
57+
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).
58+
59+
```bash
60+
devproxy
61+
```
62+
63+
### Intermittent 503 errors only
64+
65+
This configuration simulates random 503 Service Unavailable errors for 30% of requests.
66+
67+
```bash
68+
devproxy --config-file .devproxy/intermittent-errors.devproxyrc.json
69+
```
70+
71+
### Rate limiting only
72+
73+
This configuration simulates hitting rate limits with 429 Too Many Requests responses after 10 requests per minute.
74+
75+
```bash
76+
devproxy --config-file .devproxy/rate-limiting.devproxyrc.json
77+
```
78+
79+
### Slow responses only
80+
81+
This configuration adds random latency (3-5 seconds) to all responses.
82+
83+
```bash
84+
devproxy --config-file .devproxy/slow-responses.devproxyrc.json
85+
```
86+
87+
## Features
88+
89+
This sample demonstrates how to use Dev Proxy to simulate API degradation scenarios. Using this sample you can:
90+
91+
- Test your application's handling of intermittent 503 Service Unavailable errors
92+
- Verify retry logic and exponential backoff implementation
93+
- Test rate limit handling and proper use of Retry-After headers
94+
- Measure application performance under slow network conditions
95+
- Validate graceful degradation patterns in your application
96+
- Demonstrate that your error handling works before deploying to production
97+
98+
### Configuration files
99+
100+
| File | Description |
101+
|------|-------------|
102+
| `.devproxy/devproxyrc.json` | Combined configuration with all degradation scenarios |
103+
| `.devproxy/intermittent-errors.devproxyrc.json` | 503 errors at 30% failure rate |
104+
| `.devproxy/rate-limiting.devproxyrc.json` | Rate limiting at 10 requests/minute |
105+
| `.devproxy/slow-responses.devproxyrc.json` | Random latency between 3-5 seconds |
106+
| `.devproxy/errors-503.json` | Error responses for the GenericRandomErrorPlugin |
107+
| `.devproxy/mocks.json` | Mock responses for successful requests |
108+
| `index.html` | Monitoring dashboard web app |
109+
| `package.json` | Node.js configuration to run the sample |
110+
111+
### Plugins used
112+
113+
- **GenericRandomErrorPlugin** - Simulates random errors at a configurable rate
114+
- **LatencyPlugin** - Adds random delays to responses
115+
- **RateLimitingPlugin** - Simulates API rate limiting behavior
116+
- **RetryAfterPlugin** - Validates that clients respect Retry-After headers
117+
118+
## Help
119+
120+
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.
121+
122+
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.
123+
124+
If you encounter any issues using this sample, [create a new issue](https://github.com/pnp/proxy-samples/issues/new).
125+
126+
Finally, if you have an idea for improvement, [make a suggestion](https://github.com/pnp/proxy-samples/issues/new).
127+
128+
## Disclaimer
129+
130+
**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.**
131+
132+
![](https://m365-visitor-stats.azurewebsites.net/SamplesGallery/pnp-devproxy-api-degradation-scenarios)

0 commit comments

Comments
 (0)