Augustus 0.8.0
dotnet add package Augustus --version 0.8.0
NuGet\Install-Package Augustus -Version 0.8.0
<PackageReference Include="Augustus" Version="0.8.0" />
<PackageVersion Include="Augustus" Version="0.8.0" />
<PackageReference Include="Augustus" />
paket add Augustus --version 0.8.0
#r "nuget: Augustus, 0.8.0"
#:package Augustus@0.8.0
#addin nuget:?package=Augustus&version=0.8.0
#tool nuget:?package=Augustus&version=0.8.0
Augustus
A modular API simulator library for .NET. Serve static JSON, load from files, or generate realistic responses with AI — all from a lightweight local web server in your tests.
Packages
| Package | Purpose | AI Required? |
|---|---|---|
| Augustus | Core simulator — static JSON, file-based, and custom response strategies with route matching | No |
| Augustus.AI | AI-powered response generation and real-API proxy mode via OpenAI | Yes |
| Augustus.APIs.Stripe | Pre-built Stripe API defaults and fluent helpers | No |
| Augustus.Reqnroll | Reqnroll (BDD) integration with per-scenario cache isolation | No |
Quick Start
Manual mocks only (no AI, no API key)
dotnet add package Augustus
using Augustus.Extensions;
public class StripeTests
{
[Fact]
public async Task Should_Return_Customer_Data()
{
var simulator = this.CreateAPISimulator("Stripe")
.ForGet("/v1/customers/{id}")
.WithJsonFile("./mocks/customer.json")
.Add()
.ForPost("/v1/charges")
.WithResponse(new { id = "ch_123", amount = 2000, currency = "usd", status = "succeeded" })
.Add();
await simulator.StartAsync();
var client = simulator.CreateClient();
var response = await client.GetAsync("/v1/customers/cus_123");
response.StatusCode.Should().Be(HttpStatusCode.OK);
var content = await response.Content.ReadAsStringAsync();
content.Should().Contain("cus_123");
await simulator.StopAsync();
}
}
AI default handler for unmatched routes
dotnet add package Augustus.AI
using Augustus.AI;
using Augustus.Extensions;
public class StripeTests
{
[Fact]
public async Task Should_Return_Customer_Data()
{
var simulator = this.CreateStripeSimulator(opt => opt.Port = 0);
simulator.UseAI(new AIOptions
{
OpenAIApiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!
});
// Static override — always served from this JSON
simulator.ForGet("/v1/customers/cus_known")
.WithResponse(new { id = "cus_known", name = "John Doe" })
.Add();
// Everything else handled by AI
simulator.AddInstruction("Return realistic Stripe API responses");
await simulator.StartAsync();
var client = simulator.CreateClient();
// Hits the static route
var known = await client.GetStringAsync("/v1/customers/cus_known");
known.Should().Contain("John Doe");
// Falls through to AI
var generated = await client.GetStringAsync("/v1/customers/cus_other");
generated.Should().Contain("cus_other");
await simulator.StopAsync();
}
}
Per-route AI
using Augustus.AI;
simulator.ForGet("/v1/payments/{id}")
.UseAI(aiOptions, "Return a completed payment object")
.Add();
simulator.ForPost("/v1/payments")
.WithResponse(new { id = "pay_static", status = "pending" })
.Add();
Route Resolution
Requests are resolved in this order:
- Route with strategy — execute the matched
IResponseStrategy(static, file, AI, or custom) - Default handler — delegate to the AI or proxy handler (if installed via
UseAI/UseProxy) - No match, no default handler — HTTP 404 JSON error
Configuration
Core options (APISimulatorOptions)
var simulator = this.CreateAPISimulator("MyAPI", options =>
{
options.Port = 0; // 0 = auto-assign (default: 9001)
options.EnableCaching = true; // Cache AI/proxy responses (default: true)
options.CacheFolderPath = "./mocks"; // Where cache files live (default: ./mocks)
options.CacheOnly = false; // Serve only from cache, 503 on miss (default: false)
options.AutoRemoveStaleCache = true; // Clean up untouched cache files on dispose (default: true)
});
AI options (AIOptions — Augustus.AI package)
simulator.UseAI(new AIOptions
{
OpenAIApiKey = "sk-...", // Required (unless CacheOnly)
OpenAIModel = "gpt-4o-mini", // Default: gpt-4o-mini
OpenAIEndpoint = "", // Optional: custom endpoint
UseAzureOpenAI = false, // Use Azure OpenAI service
AzureDeploymentName = "", // Required when UseAzureOpenAI = true
AzureApiVersion = "2024-06-01", // Azure API version
MaxRetries = 5, // Retry attempts for transient failures
MaxConcurrentRequests = 10 // Process-wide concurrent OpenAI limit (see below)
});
OpenAI rate limits and call efficiency
Augustus.AI reduces duplicate traffic and 429 rate-limit pressure in several ways:
- Shared throttling — For a given API key (or Azure endpoint + key), model/deployment, and
MaxConcurrentRequestsvalue, all OpenAI chat completions in the process share one concurrency gate. This applies across the defaultUseAIhandler and route-levelUseAI, so parallel test classes do not each get a fullMaxConcurrentRequestsbudget in isolation. - In-flight deduplication — Concurrent requests that resolve to the same cache key (same method, path, query, normalized body, and route instructions) share a single in-flight OpenAI completion instead of fanning out.
- Retries — Transient failures (
429,5xx) use exponential backoff with jitter. When the service returns aRetry-Afterheader, the delay respects it (in addition to backoff caps fromInitialRetryDelayMs/MaxRetryDelayMs). - Proxy /
UseRealApi— Upstream HTTP calls retry on429and5xxwith the same delay settings; globalDynamicContentFieldsfromAPISimulatorOptionsare merged with per-routeWithDynamicFieldsfor cache keys. - Practical tips — For first-time cache generation, prefer a low
MaxConcurrentRequests(for example1–2) and/or run tests serially so retries do not multiply billed attempts. Use cache-only CI (CacheOnly/ committed mocks) so CI never calls OpenAI.
Response Strategies
Static JSON
simulator.ForGet("/api/health")
.WithResponse(new { status = "ok" })
.WithStatusCode(200)
.Add();
JSON file
simulator.ForGet("/v1/customers/{id}")
.WithJsonFile("./mocks/customer.json")
.Add();
Custom strategy
simulator.ForPost("/api/echo")
.WithStrategy(new MyCustomStrategy())
.Add();
AI-generated (Augustus.AI)
Route-level UseAI uses the same structured cache keys as the default AI handler (CacheKeyComputer), stores entries in the simulator’s cache folder, and still reads legacy curl-based cache files if present. Azure OpenAI is supported on routes the same way as simulator.UseAI(...).
simulator.ForGet("/v1/payments/{id}")
.UseAI(aiOptions, "Return a completed payment with realistic fields")
.Add();
Real API proxy (Augustus.AI)
simulator.ForPost("/v1/chat/completions")
.UseRealApi("https://api.openai.com", apiKey, aiOptions)
.Add();
Extension Methods
// Core (Augustus package) — no AI dependency
var sim = this.CreateAPISimulator("MyAPI");
var stripe = this.CreateStripeSimulator();
var paypal = this.CreatePayPalSimulator();
// AI-powered (Augustus.AI package)
var openai = this.CreateOpenAISimulator(opt => { opt.OpenAIApiKey = key; });
var azure = this.CreateAzureOpenAISimulator(opt => { ... });
// Proxies (Augustus.AI package)
var proxy = this.CreateOpenAIProxy(opt => { opt.OpenAIApiKey = key; });
var azureProxy = this.CreateAzureOpenAIProxy(opt => { ... });
Pass-Through Proxy Mode
Forward requests to a real upstream API, cache responses, and replay on subsequent calls. Ideal for tool/function calling scenarios.
var simulator = this.CreateAPISimulator("OpenAI Proxy");
simulator.UseProxy(
new AIOptions
{
OpenAIApiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!
},
upstreamUrl: "https://api.openai.com"
);
await simulator.StartAsync();
var client = simulator.CreateClient();
// First call: forwarded to real API, response cached
// Second call: served from cache instantly
var response = await client.PostAsync("/v1/chat/completions", content);
Cache-Only Mode
Replay cached responses without an API key or network — perfect for CI/CD.
var simulator = this.CreateAPISimulator("Stripe", options =>
{
options.CacheOnly = true;
options.CacheFolderPath = "./pre-recorded-mocks";
});
await simulator.StartAsync();
// Returns cached responses or HTTP 503 on cache miss
Reqnroll (BDD) Integration
dotnet add package Augustus.Reqnroll
using Augustus.AI;
using Augustus.Extensions;
using Augustus.Reqnroll;
using Reqnroll;
[Binding]
public class Hooks
{
private static APISimulator? _simulator;
[BeforeTestRun]
public static async Task BeforeTestRun()
{
_simulator = new Hooks().CreateStripeSimulator();
_simulator.UseAI(new AIOptions
{
OpenAIApiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!
});
_simulator.AddInstruction("Return realistic Stripe API responses");
AugustusReqnrollContext.Register(_simulator);
await _simulator.StartAsync();
}
}
Cached responses are organized per scenario:
Features/
__mocks__/
Stripe/
Scenario_Name_1/
{hash}.json
Scenario_Name_2/
{hash}.json
MyFeature.feature
Caching
Cache file names and RequestHash are derived from the HTTP method, path, query string, and a canonical form of JSON request bodies (sorted object keys at every depth, plus optional DynamicContentFields normalization). Non-JSON bodies use raw bytes. See CHANGELOG.md for release notes when this algorithm changes — upgrades can invalidate existing on-disk caches.
Augustus caches responses as JSON files:
{
"RequestHash": "A1B2C3D4E5F6G7H8",
"Response": "{\"id\": \"cus_123\", \"name\": \"John Doe\"}",
"OriginalRequest": "curl -X GET http://localhost:9001/v1/customers/cus_123",
"Instructions": ["You are a Stripe API simulator"],
"Timestamp": "2024-01-15T10:30:00Z"
}
simulator.ClearCache(); // Clear all cached responses
simulator.SetTestContext("my-scenario"); // Route cache to a subdirectory
simulator.ClearTestContext(); // Clear subdirectory and remove stale entries
Package Dependency Graph
Augustus (core) — no OpenAI dependency
└── Microsoft.AspNetCore.App (framework ref only)
Augustus.AI → Augustus
├── OpenAI (2.9.1)
└── Azure.AI.OpenAI (2.1.0)
Augustus.APIs.Stripe → Augustus
Augustus.Reqnroll → Augustus
└── Reqnroll packages
Best Practices
- Start with static mocks — use
WithResponse/WithJsonFilefor deterministic tests; add AI only where needed - Use
Port = 0— auto-assign ports to avoid conflicts in parallel test runs - Enable caching — dramatically speeds up AI-powered tests and reduces API costs
- Use cache-only in CI — commit cached responses and run without an API key
- Use
await using— ensures proper cleanup of the simulator's web server - Proxy mode for tool calling — when testing function/tool calling, use proxy mode to get real model reasoning
Building from Source
git clone https://github.com/chrisjainsley/augustus.git
cd augustus
dotnet build
dotnet test
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
If you encounter any issues or have questions:
- Search existing issues
- Create a new issue if needed
Roadmap
- Route-based response dispatch with pluggable strategies
- AI-powered response generation via OpenAI (Augustus.AI)
- Pass-through proxy mode with response caching
- Cache-only mode for CI/offline testing
- BDD integration (Reqnroll)
- Dynamic port assignment for parallel testing
- More API-specific packages (PayPal, Twilio, etc.)
- Support for more AI providers (Anthropic Claude, Google Gemini)
- Request/response validation
- Docker support
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
-
net6.0
- No dependencies.
-
net7.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Augustus:
| Package | Downloads |
|---|---|
|
Augustus.AI
OpenAI-powered extension for Augustus. Generates realistic API responses using AI and supports proxying to real APIs with caching. |
|
|
Augustus.Stripe
Stripe-specific extensions for Augustus. Provides fluent API for mocking Stripe endpoints with built-in realistic defaults. |
|
|
Augustus.Reqnroll
Reqnroll integration for Augustus API simulator. Automatically places mock caches next to feature files and organizes by scenario. |
GitHub repositories
This package is not used by any popular GitHub repositories.