RouteStub.Core
1.0.0
dotnet add package RouteStub.Core --version 1.0.0
NuGet\Install-Package RouteStub.Core -Version 1.0.0
<PackageReference Include="RouteStub.Core" Version="1.0.0" />
<PackageVersion Include="RouteStub.Core" Version="1.0.0" />
<PackageReference Include="RouteStub.Core" />
paket add RouteStub.Core --version 1.0.0
#r "nuget: RouteStub.Core, 1.0.0"
#:package RouteStub.Core@1.0.0
#addin nuget:?package=RouteStub.Core&version=1.0.0
#tool nuget:?package=RouteStub.Core&version=1.0.0
RouteStub
RouteStub is a small, convention-based HTTP stub server for .NET 10. A request path maps to folders, and two files define the response. There are no route mapping files, fluent route APIs, or custom DSLs.
Use it when an application needs to call a real HTTP endpoint during integration tests, frontend development, local development, or API prototyping.
GET /api/weather/sunny
stubs/
└── api/
└── weather/
└── sunny/
├── get.content.json
└── get.response.json
What RouteStub can do
- Serve static response bodies over real HTTP.
- Resolve URL path segments to fixture directories.
- Select fixtures by HTTP method.
- Append query parameter values to the fixture path.
- Match dynamic path or query-value segments with
~wildcards. - Prefer an exact directory match over a wildcard match at each path segment.
- Set the response status code and headers from JSON metadata.
- Infer
Content-Typefrom the content file extension. - Run as ASP.NET Core middleware, an in-process test server, or a CLI from this repository.
- Replace the filesystem repository or resolver through ASP.NET Core dependency injection.
What RouteStub cannot do
RouteStub deliberately keeps request matching and response behavior simple. It does not currently:
- Match request headers, cookies, or request bodies.
- Match query parameter names; only values participate in resolution.
- Make query parameter matching independent of parameter order.
- Generate dynamic or templated response bodies.
- Configure response delays.
- Record or proxy traffic.
- Model stateful scenarios or request sequences.
- Perform contract validation or API virtualization.
- Run scripts to calculate a response.
- Fall through to later ASP.NET Core middleware after RouteStub handles a request.
RouteStub is not intended to replace feature-rich tools such as WireMock. It is for the case where a deterministic static response is enough.
Quick start with ASP.NET Core
Install the ASP.NET Core package:
dotnet add package RouteStub.AspNetCore
Create a stubs/api/weather directory with these two files:
stubs/api/weather/get.content.json
{
"condition": "sunny",
"temperatureC": 21
}
stubs/api/weather/get.response.json
{
"statusCode": 200,
"headers": {
"X-Stub": "weather"
}
}
Mount that directory in the ASP.NET Core pipeline:
using RouteStub.AspNetCore;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseStubServer("./stubs");
app.Run();
Then request GET /api/weather. RouteStub returns the JSON content with status
200, header X-Stub: weather, and content type application/json.
The fixture directory must exist when the application starts. Relative paths are resolved from the process working directory.
Fixture reference
Directory mapping
Each decoded URL path segment maps to one directory below the fixture root. Matching is case-insensitive.
/api/users/42 → stubs/api/users/42/
An endpoint directory requires both of the following method-specific files:
<method>.content.<extension>
<method>.response.json
For example, one directory can provide different responses for GET and POST:
stubs/api/users/
├── get.content.json
├── get.response.json
├── post.content.json
└── post.response.json
File-name matching is case-insensitive. The supported method names are get,
post, patch, put, delete, head, options, trace, query, and
connect. Other HTTP methods receive 405 Method Not Allowed.
Each endpoint directory may contain exactly one content file for a given method.
If, for example, both get.content.json and get.content.txt exist, RouteStub
rejects the fixture as ambiguous instead of selecting one arbitrarily. Files
outside the exact <method>.content.<extension> shape are ignored.
Response metadata
The <method>.response.json file is required, even when the default status code
is sufficient. It accepts:
{
"statusCode": 201,
"headers": {
"Location": "/api/users/42",
"X-Environment": "stub"
}
}
statusCodedefaults to200when omitted.statusCodemust be between100and999.headersis optional and maps header names to string values.- Property names are matched case-insensitively.
- Delay, body, and matching rules are not supported in this file.
Missing fixture directories and methods without fixture files result in
404 Not Found with an empty body. Incomplete, malformed, and ambiguous fixture
configuration results in 500 Internal Server Error.
Direct core consumers receive InvalidFixtureException for a matched fixture
that is missing one of its required files or has invalid response metadata. The
exception provides a machine-readable Reason, the fixture-relative
FixturePath, and the underlying JsonException in InnerException when JSON
parsing fails:
try
{
var (stub, response) = await resolver.ResolveAsync(request);
}
catch (InvalidFixtureException exception)
{
Console.Error.WriteLine($"{exception.Reason}: {exception.FixturePath}");
Console.Error.WriteLine(exception.Message);
}
Ambiguous fixtures throw AmbiguousStubException with all conflicting names.
Content types
The extension of <method>.content.* determines the response Content-Type:
| Extensions | Content type |
|---|---|
.json |
application/json |
.xml |
application/xml |
.html, .htm |
text/html |
.pdf |
application/pdf |
.txt |
text/plain |
.css |
text/css |
.js, .mjs |
text/javascript |
.csv |
text/csv |
.yaml, .yml |
application/yaml |
.png |
image/png |
.jpg, .jpeg |
image/jpeg |
.gif |
image/gif |
.svg |
image/svg+xml |
.webp |
image/webp |
The body is returned as the file's raw bytes, so text and binary fixtures use the same convention. Other extensions are not supported.
Query parameters
Query parameter values are appended to the URL path in request enumeration order. Parameter names are not included.
GET /api/weather?city=London
stubs/
└── api/
└── weather/
└── London/
├── get.content.json
└── get.response.json
For multiple parameters, create one nested directory per parameter value:
GET /search?category=books&page=2
→ stubs/search/books/2/
Because names are ignored, ?city=London and ?country=London resolve to the
same fixture. Because values are appended in enumeration order, clients should
send multiple parameters in a consistent order.
Wildcards
Use ~ inside a directory name to match zero or more characters in one path
segment. A directory named only ~ matches any single segment.
stubs/api/users/
├── 42/
│ ├── get.content.json
│ └── get.response.json
└── ~/
├── get.content.json
└── get.response.json
GET /api/users/42 uses the exact 42 directory. Other IDs, such as
GET /api/users/99, use ~. Names such as user-~ are also valid patterns.
Wildcards match one directory level at a time; they do not consume multiple URL segments. An exact directory always wins without evaluating wildcard matches. If no exact directory exists and multiple wildcard directories match the same segment, RouteStub rejects the fixture as ambiguous and reports every matching directory.
Hosting options
All hosting options use the same resolver and fixture conventions.
ASP.NET Core middleware
For the shortest setup, call UseStubServer with a fixture path as shown in the
quick start.
Use service registration when the path comes from configuration or the
application provides a custom IStubRepository or IStubResolver:
using RouteStub.AspNetCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddStubServer(options =>
{
options.FixturePath = "./stubs";
});
var app = builder.Build();
app.UseStubServer();
app.Run();
The default repository and resolver are registered only when replacements are not already present in the service collection.
UseStubServer is terminal middleware: it responds to every request and does
not call the next component. Register logging, authentication, CORS, or other
middleware that must run for stub requests before it. Do not mount it in front
of application endpoints that must remain reachable.
Integration tests
Install the framework-neutral test server package:
dotnet add package RouteStub.Testing
Start a real loopback HTTP server on an available port and point the client under test at it:
using RouteStub.Testing;
await using var server = await RouteStubTestServer.StartAsync("./stubs");
using var client = new HttpClient
{
BaseAddress = server.BaseAddress
};
var response = await client.GetAsync("api/weather");
RouteStubTestServer supports startup cancellation and IAsyncDisposable. It
does not depend on MSTest, xUnit, NUnit, or another test framework.
In-process server
Install RouteStub.Server when non-test application code needs to start and
control a server directly:
dotnet add package RouteStub.Server
using RouteStub.Server;
await using var server = await StubServer.StartAsync("./stubs");
Console.WriteLine(server.BaseAddress);
Without a URL, StubServer listens on loopback using an available ephemeral
port. Pass a URL as the second argument to select an address explicitly.
CLI from this repository
The CLI project is currently run from source. It defaults to the stubs
directory and http://localhost:5000:
dotnet run --project src\RouteStub.Cli -- serve
Select another fixture directory or URL:
dotnet run --project src\RouteStub.Cli -- serve .\fixtures --url http://localhost:5050
Packages and requirements
RouteStub currently targets .NET 10.
| Package | Use it for |
|---|---|
RouteStub.AspNetCore |
Mounting RouteStub in an ASP.NET Core pipeline |
RouteStub.Testing |
Starting a framework-neutral server in integration tests |
RouteStub.Server |
Starting and controlling an in-process server directly |
RouteStub.Core |
Resolver models and custom repository/resolver implementations |
Samples
Complete ASP.NET Core and integration-test examples are in
samples.
dotnet build samples\RouteStub.Samples.slnx
dotnet test samples\RouteStub.Testing.Sample
dotnet run --project samples\RouteStub.AspNetCore.Sample
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on RouteStub.Core:
| Package | Downloads |
|---|---|
|
RouteStub.AspNetCore
ASP.NET Core service registration and middleware for convention-based RouteStub HTTP fixtures. |
GitHub repositories
This package is not used by any popular GitHub repositories.