ApiTestSpark 1.7.0
See the version list below for details.
dotnet add package ApiTestSpark --version 1.7.0
NuGet\Install-Package ApiTestSpark -Version 1.7.0
<PackageReference Include="ApiTestSpark" Version="1.7.0" />
<PackageVersion Include="ApiTestSpark" Version="1.7.0" />
<PackageReference Include="ApiTestSpark" />
paket add ApiTestSpark --version 1.7.0
#r "nuget: ApiTestSpark, 1.7.0"
#:package ApiTestSpark@1.7.0
#addin nuget:?package=ApiTestSpark&version=1.7.0
#tool nuget:?package=ApiTestSpark&version=1.7.0
ApiTestSpark
API Test Spark is a Make Bold Spark API testing workbench, fully owned and managed by Make Bold Solutions.
Embed the branded React SPA into any .NET 10 Minimal API with a single method call.
Autodiscovers your OpenAPI v3 endpoints and renders a full-featured interactive test harness at /api-test-spark/.
Live Demo · Make Bold Spark · GitHub · NuGet
Install
dotnet add package ApiTestSpark
Quickstart
using ApiTestSpark;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
var app = builder.Build();
app.MapOpenApi(); // /openapi/v1.json
app.MapApiTestSpark(); // /api-test-spark/
app.Run();
Navigate to https://localhost:{port}/api-test-spark/ — the harness autodiscovers all your endpoints.
Configuration
All options are optional. Pass an Action<ApiTestSparkOptions> to configure:
app.MapApiTestSpark(options =>
{
options.OpenApiUrl = "/openapi/v1.json"; // default: "/openapi.json"
options.AuthScheme = "Bearer"; // pre-populates auth field
options.DefaultHeaders["X-Tenant-Id"] = "acme"; // injected into every SPA request
options.Environments = ["Development", "Staging"]; // empty = all environments
options.EnableDemoIntegrations = false; // hide JokeAPI + JSONPlaceholder
});
Options reference
| Property | Default | Description |
|---|---|---|
OpenApiUrl |
"/openapi.json" |
URL of your OpenAPI v3 JSON document. null disables autodiscovery. |
AuthScheme |
null |
"Bearer", "ApiKey", or "Basic" — metadata only, never a token value. |
DefaultHeaders |
{} |
Headers injected into every host API SPA request. Must not contain credentials — values are served publicly via the config endpoint. Supports identity tokens below. |
Environments |
[] (all) |
Environment names where the harness is active. Empty = everywhere. Example: ["Development", "Staging"] keeps it off production. |
CorsOrigins |
[] (same-origin) |
Extra origins allowed to call the config endpoint. Use when the Vite dev server and .NET API run on different ports. |
EnableVerboseLogging |
false |
Emits ILogger.LogDebug for every asset served and SPA fallback. Alternatively set Logging:LogLevel:ApiTestSpark=Debug in appsettings. |
EnableDemoIntegrations |
true |
When false, hides the built-in JokeAPI and JSONPlaceholder demo screens from the home page and disables their routes. Set to false to present a clean harness showing only your host API and API Doc Builder. |
RemoteApiProfiles |
[] |
List of named remote APIs. Each profile has Id, Name, Description, RemoteBaseUrl, RemoteOpenApiUrl, credentials, and default headers. |
EnableRemoteCallProxy |
false |
Routes endpoint calls for server-configured remote profiles through the host API, avoiding browser CORS requirements. See the security note below. |
RemoteBaseUrl |
null |
Legacy single-remote base URL. Used as one compatibility profile when RemoteApiProfiles is empty. |
RemoteOpenApiUrl |
null |
Legacy single-remote OpenAPI URL. Used as one compatibility profile when RemoteApiProfiles is empty. |
RemoteOpenApiApiKeyHeader |
null |
Legacy header name for the remote API key. |
RemoteOpenApiApiKeyValue |
null |
Legacy API key value. Used server-side only and redacted from config. |
RemoteOpenApiBearerToken |
null |
Legacy bearer token. Used server-side only and redacted from config. |
RemoteDefaultHeaders |
{} |
Legacy headers injected into browser-side requests to the remote API. Supports identity tokens below plus {session-guid} and {request-guid}. |
Identity header tokens
Use these tokens only in explicitly configured request headers. They are resolved when
/api-test-spark/config is requested and may expose identity data to downstream APIs.
Unauthenticated or unresolved values become an empty string.
| Token | Resolution order |
|---|---|
{user-name} |
Identity.Name → name → preferred_username |
{user-email} |
ClaimTypes.Email → email → preferred_username |
{user-id} |
ClaimTypes.NameIdentifier → sub → oid |
preferred_username is used as an email fallback only when the identity provider
guarantees that it contains an email address or UPN.
Server-side remote call proxy
By default, remote endpoint calls run directly from the browser and the remote API
must allow the harness origin with CORS. Set EnableRemoteCallProxy = true to route
calls for server-configured RemoteApiProfiles through
/api-test-spark/remote-call; browser-created profiles always remain browser-direct.
app.MapApiTestSpark(options =>
{
options.EnableRemoteCallProxy = true;
options.RemoteApiProfiles.Add(new RemoteApiProfile
{
Id = "make-bold-spark",
RemoteBaseUrl = "https://makeboldspark.com",
RemoteOpenApiUrl = "https://makeboldspark.com/openapi/v1.json",
});
});
Security: enabling this makes the host application an HTTP proxy for each configured profile. The proxy accepts only configured profile IDs and only forwards to that profile's base origin; it does not accept arbitrary remote URLs. Review every enabled profile, protect the harness route with your normal application authentication, and do not enable it for untrusted remote targets. Server-held API credentials are applied by the host and remain redacted from browser configuration.
Multiple remote APIs
Configure named profiles in Program.cs:
app.MapApiTestSpark(options =>
{
options.RemoteApiProfiles.Add(new RemoteApiProfile
{
Id = "orders-api",
Name = "Orders API",
Description = "Order management endpoints.",
RemoteBaseUrl = "https://orders.example.com",
RemoteOpenApiUrl = "https://orders.example.com/openapi.json",
RemoteOpenApiApiKeyHeader = "x-api-key",
RemoteOpenApiApiKeyValue = builder.Configuration["Orders:ApiKey"],
});
});
Server profile credentials are redacted from /api-test-spark/config and used only by /api-test-spark/remote-spec?profileId=.... When EnableRemoteCallProxy = true, server-configured profiles can also send endpoint calls through /api-test-spark/remote-call to avoid browser CORS requirements. Browser-created profiles on the Config page are stored locally, fetch OpenAPI documents directly from the browser, and keep endpoint calls browser-direct.
Features
- Make Bold Spark branded UI — Make Bold Solutions colors, package icon, favicon, logo assets, and Inter Tight typography are embedded with the harness.
- OpenAPI autodiscovery — endpoints grouped by tag in a collapsible accordion; real-time search filter
- Remote API Explorer — browse and test one or more named remote REST APIs from their OpenAPI documents; server-configured credentials stay server-side, browser-created profiles stay local, and duplicate visible names are blocked before save
- Server-side remote call proxy — enable
EnableRemoteCallProxyto route endpoint calls for server-configured profiles through the host app instead of requiring the remote API to allow browser CORS - Identity-aware header templates — configured host and remote headers can expand
{user-name},{user-email}, and{user-id}from the authenticated user when the config payload is generated - Full metadata surface — descriptions rendered as markdown, response codes as coloured badges with expandable inline schemas,
operationIdas a copyable chip, schema constraint tables - JSON scaffold — request body pre-filled from
example → default → enum[0] → type placeholder; nested objects and arrays scaffolded recursively - Response rendering — arrays as sortable tables, objects as editable forms, primitives in pre blocks
- API Doc Builder (
/api-docs) — select endpoints, capture live curl + responses, annotate sections, export markdown - Remote API Doc Builder (
/remote-docs/{profileId}) — same documentation capture for remote API endpoints - Header token expansion —
{session-guid},{request-guid},{user-name},{user-email}, and{user-id}tokens in header values are replaced with request/session/user-specific values - Debug panel — drag-resizable, captures every request/response/error/metric; cURL snippet per request; FIFO buffered
- Environment gating — one option keeps the harness off production
- Demo integration toggle — set
EnableDemoIntegrations = falseto hide the built-in JokeAPI and JSONPlaceholder screens; show only your host API and the API Doc Builder - Zero extra dependencies — branded embedded package, no
wwwrootchanges, nothing copied to your project
Clean install — your API only
Set EnableDemoIntegrations = false to remove the JokeAPI and JSONPlaceholder demo screens entirely.
The home page shows only Host API Explorer and API Doc Builder — no sample data, no external API noise.
app.MapApiTestSpark(options =>
{
options.OpenApiUrl = "/openapi/v1.json";
options.Environments = ["Development", "Staging"];
options.EnableDemoIntegrations = false;
});
Remote API Profiles
Point the harness at one or more remote REST APIs by configuring RemoteApiProfiles. Each profile gets its own explorer and doc builder route, displayed by Name and Description. Server-configured specs are fetched through /api-test-spark/remote-spec?profileId=... with credential values held server-side and redacted from /api-test-spark/config. Browser-created profiles are managed on the Config page, stored in localStorage, receive GUID ids, and fetch OpenAPI documents directly from the browser. Visible profile names must be unique, so users get a clear validation message before saving duplicates.
app.MapApiTestSpark(options =>
{
options.OpenApiUrl = "/openapi/v1.json";
options.RemoteApiProfiles.Add(new RemoteApiProfile
{
Id = "partner-api",
Name = "Partner API",
Description = "External partner integration endpoints.",
RemoteBaseUrl = "https://api.example.com",
RemoteOpenApiUrl = "https://api.example.com/openapi.json",
RemoteOpenApiApiKeyHeader = "x-api-key",
RemoteOpenApiApiKeyValue = "your-api-key",
RemoteDefaultHeaders =
{
["correlationId"] = "{request-guid}",
["sessionId"] = "{session-guid}",
},
});
});
Security note: The harness is intended for local and trusted development environments only. Do not expose it to the public internet.
Getting the most out of API Test Spark
API Test Spark reads your OpenAPI v3 document. Every annotation you add to your API is surfaced directly in the harness. The more metadata you provide, the richer the testing experience.
Tag endpoints with "Namespace: Label" format — creates a two-level collapsible accordion:
app.MapGroup("/products").WithTags("Products: Catalog").MapProducts();
app.MapGroup("/orders").WithTags("Orders: Lifecycle").MapOrders();
Name, summarise, and describe every operation — summary is the card title; description renders as markdown:
group.MapGet("/{id}", GetById)
.WithName("GetProductById")
.WithSummary("Get a product by ID")
.WithDescription("Returns a single product. Seeded IDs are **1–10**. Returns **404** if not found.");
Declare every response code — each becomes a coloured badge with an expandable inline schema:
.Produces<Product>(StatusCodes.Status200OK)
.Produces(StatusCodes.Status404NotFound)
Or use TypedResults — it infers response types automatically without extra .Produces() calls.
Annotate your schema types — [Description], [Required], [Range], [MinLength], [MaxLength] all appear as columns in the schema property table:
public record Product(
[property: Description("Display name.")][property: Required][property: MaxLength(100)]
string Name,
[property: Description("Unit price in USD.")][property: Range(0.01, 99999.99)]
decimal Price
);
Set examples or defaults — the JSON scaffold fills from example → default → enum[0] → type placeholder. Without examples every field shows a generic placeholder; with them testers can fire requests immediately.
Add a workflow walkthrough to info.description — renders as markdown in the API info header; ideal for linking resource groups and describing end-to-end flows.
See the live demo and full best-practices guide for annotated source examples.
Reverse proxy
Call UseForwardedHeaders() before MapApiTestSpark() so the config endpoint reports the correct public base URL:
app.UseForwardedHeaders();
app.MapApiTestSpark();
Local development (Vite dev server)
If your React dev server and .NET API run on different ports, allow the dev origin:
app.MapApiTestSpark(options =>
{
options.CorsOrigins = ["http://localhost:5151"];
});
Diagnostics
{
"Logging": {
"LogLevel": {
"ApiTestSpark": "Debug"
}
}
}
License
| 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
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
1.7.0 — Remote API profiles can now proxy endpoint calls through the host app with
the new EnableRemoteCallProxy option, keeping server-held credentials off the browser and avoiding
remote CORS requirements for server-configured profiles. The release also adds resolved userName,
userEmail, and userId metadata to the config payload for identity-aware header templates, hardens
remote profile management so Program.cs profiles remain authoritative, and improves path-parameter
validation across the host and remote explorers. See CHANGELOG.md for full history.