diff --git a/samples/api-degradation-scenarios/.devproxy/devproxyrc.json b/samples/api-degradation-scenarios/.devproxy/devproxyrc.json new file mode 100644 index 0000000..d25e46d --- /dev/null +++ b/samples/api-degradation-scenarios/.devproxy/devproxyrc.json @@ -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" + } +} diff --git a/samples/api-degradation-scenarios/.devproxy/errors-503.json b/samples/api-degradation-scenarios/.devproxy/errors-503.json new file mode 100644 index 0000000..53ef564 --- /dev/null +++ b/samples/api-degradation-scenarios/.devproxy/errors-503.json @@ -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." + } + } + } + ] + } + ] +} diff --git a/samples/api-degradation-scenarios/.devproxy/intermittent-errors.devproxyrc.json b/samples/api-degradation-scenarios/.devproxy/intermittent-errors.devproxyrc.json new file mode 100644 index 0000000..dad5699 --- /dev/null +++ b/samples/api-degradation-scenarios/.devproxy/intermittent-errors.devproxyrc.json @@ -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" + } +} diff --git a/samples/api-degradation-scenarios/.devproxy/mocks.json b/samples/api-degradation-scenarios/.devproxy/mocks.json new file mode 100644 index 0000000..70897cc --- /dev/null +++ b/samples/api-degradation-scenarios/.devproxy/mocks.json @@ -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" + } + } + } + ] +} diff --git a/samples/api-degradation-scenarios/.devproxy/rate-limiting.devproxyrc.json b/samples/api-degradation-scenarios/.devproxy/rate-limiting.devproxyrc.json new file mode 100644 index 0000000..e718218 --- /dev/null +++ b/samples/api-degradation-scenarios/.devproxy/rate-limiting.devproxyrc.json @@ -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" + } +} diff --git a/samples/api-degradation-scenarios/.devproxy/slow-responses.devproxyrc.json b/samples/api-degradation-scenarios/.devproxy/slow-responses.devproxyrc.json new file mode 100644 index 0000000..f8abb21 --- /dev/null +++ b/samples/api-degradation-scenarios/.devproxy/slow-responses.devproxyrc.json @@ -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" + } +} diff --git a/samples/api-degradation-scenarios/README.md b/samples/api-degradation-scenarios/README.md new file mode 100644 index 0000000..e1a1420 --- /dev/null +++ b/samples/api-degradation-scenarios/README.md @@ -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) diff --git a/samples/api-degradation-scenarios/assets/sample.json b/samples/api-degradation-scenarios/assets/sample.json new file mode 100644 index 0000000..173d994 --- /dev/null +++ b/samples/api-degradation-scenarios/assets/sample.json @@ -0,0 +1,87 @@ +[ + { + "name": "pnp-devproxy-api-degradation-scenarios", + "source": "pnp", + "title": "Simulate API degradation scenarios", + "shortDescription": "This sample demonstrates how to simulate various API degradation scenarios including intermittent errors, rate limiting, and slow responses to test your application's resilience.", + "url": "https://github.com/pnp/proxy-samples/tree/main/samples/api-degradation-scenarios", + "downloadUrl": "https://pnp.github.io/download-partial/?url=https://github.com/pnp/proxy-samples/tree/main/samples/api-degradation-scenarios", + "longDescription": [ + "This sample demonstrates how to simulate various API degradation scenarios including intermittent errors, rate limiting, and slow responses to test your application's resilience." + ], + "creationDateTime": "2026-01-18", + "updateDateTime": "2026-01-18", + "products": [ + "Dev Proxy" + ], + "metadata": [ + { + "key": "SAMPLE ID", + "value": "api-degradation-scenarios" + }, + { + "key": "PRESET", + "value": "No" + }, + { + "key": "MOCKS", + "value": "Yes" + }, + { + "key": "PLUGIN", + "value": "No" + }, + { + "key": "PROXY VERSION", + "value": "v2.0.0" + } + ], + "thumbnails": [ + { + "type": "image", + "order": 100, + "url": "https://github.com/pnp/proxy-samples/raw/main/samples/api-degradation-scenarios/assets/screenshot.png", + "alt": "Dev Proxy simulating API degradation scenarios" + } + ], + "authors": [ + { + "gitHubAccount": "waldekmastykarz", + "pictureUrl": "https://github.com/waldekmastykarz.png", + "name": "Waldek Mastykarz" + } + ], + "references": [ + { + "name": "Get started with the Dev Proxy", + "description": "The tutorial will introduce you to the Dev Proxy and show you how to use its features.", + "url": "https://learn.microsoft.com/microsoft-cloud/dev/dev-proxy/get-started" + }, + { + "name": "Use preset configurations", + "description": "Instructions on how to configure the Dev Proxy to use a different configuration file.", + "url": "https://learn.microsoft.com/microsoft-cloud/dev/dev-proxy/how-to/use-preset-configurations" + }, + { + "name": "GenericRandomErrorPlugin", + "description": "Technical reference for the GenericRandomErrorPlugin.", + "url": "https://learn.microsoft.com/microsoft-cloud/dev/dev-proxy/technical-reference/genericrandomerrorplugin" + }, + { + "name": "RateLimitingPlugin", + "description": "Technical reference for the RateLimitingPlugin.", + "url": "https://learn.microsoft.com/microsoft-cloud/dev/dev-proxy/technical-reference/ratelimitingplugin" + }, + { + "name": "LatencyPlugin", + "description": "Technical reference for the LatencyPlugin.", + "url": "https://learn.microsoft.com/microsoft-cloud/dev/dev-proxy/technical-reference/latencyplugin" + }, + { + "name": "Test my app with random errors", + "description": "How to test your app with random errors.", + "url": "https://learn.microsoft.com/microsoft-cloud/dev/dev-proxy/how-to/test-my-app-with-random-errors" + } + ] + } +] diff --git a/samples/api-degradation-scenarios/assets/screenshot.png b/samples/api-degradation-scenarios/assets/screenshot.png new file mode 100644 index 0000000..39e4ba4 Binary files /dev/null and b/samples/api-degradation-scenarios/assets/screenshot.png differ diff --git a/samples/api-degradation-scenarios/index.html b/samples/api-degradation-scenarios/index.html new file mode 100644 index 0000000..8e3a871 --- /dev/null +++ b/samples/api-degradation-scenarios/index.html @@ -0,0 +1,517 @@ + + + + + + + API Degradation Scenarios - Monitoring Dashboard + + + + +
+

🔥 API Degradation Scenarios

+ +
+ How it works: This dashboard makes requests to https://api.example.com/data through Dev Proxy. + Dev Proxy intercepts these requests and simulates various degradation scenarios including 503 errors (30% rate), + rate limiting (429 after 10 requests/minute), and slow responses (3-5s latency). +

+ Start Dev Proxy first: devproxy +
+ +
+
+

Total Requests

+
0
+
+
+

Pending

+
0
+
+
+

Success Rate

+
100%
+
+
+

Avg Response Time

+
0ms
+
+
+

Errors (503)

+
0
+
+
+

Rate Limited (429)

+
0
+
+
+

Other Errors

+
0
+
+
+

Successful (2xx)

+
0
+
+
+ +
+ + + + + +
+ +
+

Response Distribution

+
+ Success (2xx) +
+
+
+ 0% +
+
+ Error (503) +
+
+
+ 0% +
+
+ Rate Limit (429) +
+
+
+ 0% +
+
+ Other Errors +
+
+
+ 0% +
+
+ +
+

Request Log

+
+
+
+ + + + + diff --git a/samples/api-degradation-scenarios/package.json b/samples/api-degradation-scenarios/package.json new file mode 100644 index 0000000..15ac450 --- /dev/null +++ b/samples/api-degradation-scenarios/package.json @@ -0,0 +1,17 @@ +{ + "name": "api-degradation-scenarios", + "version": "1.0.0", + "description": "Demo web app to test API degradation scenarios with Dev Proxy", + "main": "index.html", + "scripts": { + "start": "npx concurrently \"npx http-server -p 3000\" \"devproxy\"" + }, + "keywords": [ + "dev-proxy", + "api-testing", + "degradation", + "resilience" + ], + "author": "Waldek Mastykarz", + "license": "ISC" +}