Lyo.Config.Api
1.0.1
dotnet add package Lyo.Config.Api --version 1.0.1
NuGet\Install-Package Lyo.Config.Api -Version 1.0.1
<PackageReference Include="Lyo.Config.Api" Version="1.0.1" />
<PackageVersion Include="Lyo.Config.Api" Version="1.0.1" />
<PackageReference Include="Lyo.Config.Api" />
paket add Lyo.Config.Api --version 1.0.1
#r "nuget: Lyo.Config.Api, 1.0.1"
#:package Lyo.Config.Api@1.0.1
#addin nuget:?package=Lyo.Config.Api&version=1.0.1
#tool nuget:?package=Lyo.Config.Api&version=1.0.1
Lyo.Config.Api
HTTP host for central app configuration backed by PostgreSQL and Lyo.Config. Microservices resolve merged config per deployment identity and poll using ETags or an optional version query mirror.
Resolution contracts (ConfigResolveConditionalResult) live in Lyo.Config.Api.Models. The HTTP typed client and AddConfigApiClientFromConfiguration live in Lyo.Config.Api.Client (readme). Route slug → EntityRef mapping uses AppConfigEntity from Lyo.Config. Polling plus IOptionsMonitor<T> is Lyo.Config.Api.Hosting.
Examples
Host embedding (DI + middleware pipeline)
using Lyo.Config.Api;
using Lyo.Config.Api.Security;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddConfigApi(builder.Configuration);
var app = builder.Build();
app.UseMiddleware<RequireConfigApiKeyMiddleware>(); // BEFORE MapConfigApiEndpoints
app.MapConfigApiEndpoints(); // default prefix /api/config
app.Run();
Examples (curl)
# Latest snapshot
curl -sS "http://localhost:5088/api/config/gateway/prod-west"
# Lightweight metadata only
curl -sSI "http://localhost:5088/api/config/gateway/prod-west"
# Poll with previous ETag (quoted)
ETAG='"A1B2C3..."'
curl -sSI -H "If-None-Match: $ETAG" "http://localhost:5088/api/config/gateway/prod-west"
# Same using version= (bare hex, no quotes)
curl -sSI "http://localhost:5088/api/config/gateway/prod-west?version=A1B2C3D4..."
Host embedding (DI + middleware pipeline)
Lyo.Config.Api is structured so it can run standalone (see Lyo.Config.Api.Host) or be embedded into another host that already owns the WebApplication pipeline. The full surface is
two extensions plus one middleware, all in Lyo.Config.Api:
| Member | Defined in | Purpose |
|---|---|---|
services.AddConfigApi(IConfiguration) |
Extensions.cs |
Registers IConfigStore via AddPostgresConfigStoreFromConfiguration, binds ConfigApiSecurityOptions (section ConfigApiSecurity) and ConfigApiHostingOptions (section ConfigApiHosting). |
app.MapConfigApiEndpoints(prefix = "/api/config") |
Extensions.cs |
Returns a RouteGroupBuilder and mounts the manage/* and {appKind}/{appId} route groups under prefix. The default prefix is /api/config; pass another value to relocate the whole API. |
UseMiddleware<RequireConfigApiKeyMiddleware>() |
Security/RequireConfigApiKeyMiddleware.cs |
Path-scoped API-key gate (see below). Must run before MapConfigApiEndpoints in the request pipeline. |
Composition in the standalone host (and the pattern any embedding host should follow):
RequireConfigApiKeyMiddleware ordering and behavior
- Registered as a pipeline middleware (not an authorization filter). It checks
HttpContext.Request.Path.StartsWithSegments("/api/config", …)and silently passes through any request outside that prefix. If you relocate the API by passing a non-default prefix toMapConfigApiEndpoints, the middleware will not match it —/api/configis the hard-coded path check. - When
ConfigApiSecurity.RequireApiKey == false, the middleware short-circuits to_nextwithout inspecting headers. TogglingRequireApiKeytotruerequires the host to configure a non-emptyApiKey; otherwise matching requests get500 Internal Server Errorwith{ "detail": "API key enforcement is enabled but no server key has been configured." }. - When enabled, the middleware accepts the secret via
X-Api-Key: <value>orAuthorization: Bearer <value>(other schemes are rejected). Comparison usesCryptographicOperations.FixedTimeEqualsover UTF-8 bytes; missing / empty / mismatching credentials produce401 Unauthorizedwith no body. - Place this middleware after any TLS termination / proxy header middleware and before any logging that might leak request bodies, since it always returns before the endpoint runs on rejection.
Security options (ConfigApiSecurityOptions, section ConfigApiSecurity)
| Key | Type | Default | Purpose |
|---|---|---|---|
ConfigApiSecurity:RequireApiKey |
bool |
false |
Master switch. When false, all routes are anonymous and the middleware is a no-op. |
ConfigApiSecurity:ApiKey |
string |
"" |
Shared secret compared in constant time. Must be non-empty when RequireApiKey == true. |
Note: there is no authorization policy or scopes/role check inside this project — only the constant-time secret comparison above. If you need finer-grained access control, register your own auth middleware before
RequireConfigApiKeyMiddleware, or replace it entirely.
Hosting options (ConfigApiHostingOptions, section ConfigApiHosting)
| Key | Type | Default | Purpose |
|---|---|---|---|
ConfigApiHosting:PollIntervalAdvisoryMilliseconds |
int? |
null |
When > 0, emitted on every resolve response as the X-Config-Poll-Interval-Ms header. Purely advisory — clients are free to ignore it. |
How routes map to Lyo.Config
All API traffic for app config uses a single store entity type App (AppConfigEntity.AppEntityType).
| URL segment | Meaning |
|---|---|
{appKind} |
Taxonomy for the process (e.g. api, gateway, worker). Lowercase slug: letters, digits, -, _, . |
{appId} |
Instance id (e.g. checkout, 550e8400-e29b-41d4-a716-446655440000). Same slug rules after URL decode. |
Persisted compound id:
EntityType = "App"
EntityId = "{appKind}:{appId}" // e.g. gateway:prod-west
Definitions you create with PUT /manage/definitions should use forEntityType: "App". Bindings must use the same App + that compound forEntityId, or use
the manage routes below.
Runtime: resolve and poll
Base path (default): /api/config.
Runtime: resolve and poll — GET, HEAD, POST — /{appKind}/{appId}
HEAD: sameETag/ 304 behaviour, no body on 200.POST: same body asGETwhen you prefer not to put long ids in query strings.
Management (/api/config/manage)
Requires the same auth as the rest of /api/config when ConfigApiSecurity.RequireApiKey is true (X-Api-Key or Authorization: Bearer).
| Method | Path | Notes |
|---|---|---|
| GET | /definitions |
Lists definitions for App. |
| PUT | /definitions |
Body: ConfigDefinitionRecord (forEntityType should be App). |
| DELETE | /definitions/{definitionId} |
|
| PUT | /bindings |
Body: ConfigBindingRecord (forEntityType App, forEntityId kind:id e.g. gateway:prod-west). |
| DELETE | /bindings/{bindingId} |
|
| GET | /bindings/{bindingId}/revisions |
|
| POST | /bindings/{bindingId}/revert |
Body: { "revision": <int> } |
| GET | /apps/{appKind}/{appId}/bindings |
Convenience list for one app identity. |
| GET | /apps/{appKind}/{appId}/bindings/{key}/revisions |
|
| POST | /apps/{appKind}/{appId}/bindings/{key}/revert |
Body: { "revision": <int> } |
Configuration (appsettings)
PostgresConfig: connection string and migrations forLyo.Config.Postgres.ConfigApiHosting: optionalPollIntervalAdvisoryMilliseconds(see Host embedding → Hosting options above).ConfigApiSecurity:RequireApiKey,ApiKey(see Host embedding → Security options above).
C# consumer (Lyo.Config.Api.Client)
Register the typed client:
using Lyo.Config.Api.Client;
services.AddConfigApiClientFromConfiguration(configuration);
// Alternate section binding:
// services.AddConfigApiClientFromConfiguration(configuration, configSectionName: "MyConfigApi");
var resolved = await configClient.ResolveForAppAsync(
appKind: "gateway",
appId: "prod-west",
ifNoneMatch: lastEtag,
version: null,
headOnly: false,
cancellationToken: ct);
// Background poll
var merged = await ConfigPolling.PollUntilChangedAsync(
configClient,
appKind: "api",
appId: "checkout",
ifNoneMatch: null,
delayWhenNotModified: TimeSpan.FromSeconds(15),
cancellationToken: ct);
Bind ConfigApi in configuration for BaseUrl, optional ApiKey, PollInterval, etc. (
ConfigApiClientOptions). More examples: Lyo.Config.Api.Client/README.md.
Local run
dotnet run --project Lyo.Net/Apps/Config/Lyo.Config.Api/Lyo.Config.Api.csproj
Development OpenAPI document: /openapi/v1.json (ASP.NET convention). Scalar UI is mapped when the environment is Development.
See also
- Feature docs:
Lyo.Config/README.md
Dependencies
Generated from ProjectReference / PackageReference (same model as docs/Lyo.ProjectGraph.html).
Lyo.Api— (direct, lyo)Lyo.Authentication— (direct, lyo)Lyo.Authentication.AspNetCore— (direct, lyo)Lyo.Authentication.Google— (direct, lyo)Lyo.Authentication.Keycloak— (direct, lyo)Lyo.Authentication.OpenIdConnect— (direct, lyo)Lyo.Authentication.Postgres— (direct, lyo)Lyo.Config— (direct, lyo)Lyo.Config.Postgres— (direct, lyo)Lyo.EntityReference.Models— (direct, lyo)Lyo.Api.Models— (transitive, lyo)Lyo.Authentication.Models— (transitive, lyo)Lyo.Cache— (transitive, lyo)Lyo.Common— (transitive, lyo)Lyo.Compression— (transitive, lyo)Lyo.DateAndTime— (transitive, lyo)Lyo.Diagnostic— (transitive, lyo)Lyo.Diagnostic.AspNetCore— (transitive, lyo)Lyo.Diff— (transitive, lyo)Lyo.Encryption— (transitive, lyo)Lyo.EntityReference.Postgres— (transitive, lyo)Lyo.Exceptions— (transitive, lyo)Lyo.Formatter— (transitive, lyo)Lyo.Hashing— (transitive, lyo)Lyo.Health— (transitive, lyo)Lyo.KeyStore— (transitive, lyo)Lyo.Metrics— (transitive, lyo)Lyo.PackageMetadata— (transitive, lyo)Lyo.Postgres— (transitive, lyo)Lyo.Query— (transitive, lyo)Lyo.Query.Models— (transitive, lyo)Lyo.Result— (transitive, lyo)Lyo.Streams— (transitive, lyo)Lyo.Validation— (transitive, lyo)BouncyCastle.Cryptography2.6.2— (transitive, third-party, netstandard2.0)EasyCompressor2.1.0— (transitive, third-party)Konscious.Security.Cryptography.Argon21.3.1— (transitive, third-party)Microsoft.AspNetCore.Authorization10.0.5— (transitive, microsoft)Microsoft.AspNetCore.Http.Abstractions2.*— (transitive, microsoft)Microsoft.AspNetCore.OpenApi10.0.5— (transitive, microsoft)Microsoft.Bcl.AsyncInterfaces10.0.5— (transitive, microsoft, netstandard2.0)Microsoft.EntityFrameworkCore10.0.5— (transitive, microsoft)Microsoft.EntityFrameworkCore.Analyzers10.0.5— (transitive, microsoft)Microsoft.EntityFrameworkCore.Design10.0.5— (transitive, microsoft)Microsoft.EntityFrameworkCore.Relational10.0.5— (transitive, microsoft)Microsoft.Extensions.Caching.Memory10.0.5— (transitive, microsoft)Microsoft.Extensions.Configuration.Binder10.0.5— (transitive, microsoft)Microsoft.Extensions.DependencyInjection10.0.5— (transitive, microsoft)Microsoft.Extensions.DependencyInjection.Abstractions10.0.5— (transitive, microsoft, net10.0, netstandard2.0)Microsoft.Extensions.Hosting.Abstractions10.0.5— (transitive, microsoft)Microsoft.Extensions.Logging.Abstractions10.0.5— (transitive, microsoft)Microsoft.Extensions.Options10.0.5— (transitive, microsoft)Microsoft.Extensions.Options.ConfigurationExtensions10.0.5— (transitive, microsoft)Npgsql.EntityFrameworkCore.PostgreSQL10.0.3— (transitive, third-party)SmartFormat.NET3.6.1— (transitive, third-party)System.Buffers4.6.1— (transitive, microsoft, netstandard2.0)System.ComponentModel.Annotations5.0.0— (transitive, microsoft)System.IO.Hashing10.0.5— (transitive, microsoft, net10.0)System.Memory4.6.3— (transitive, microsoft, netstandard2.0)System.Text.Json10.0.5— (transitive, microsoft, netstandard2.0)System.Threading.Tasks.Extensions4.6.3— (transitive, microsoft, netstandard2.0)
| 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
- Lyo.Api (>= 1.0.1)
- Lyo.Authentication (>= 1.0.1)
- Lyo.Authentication.AspNetCore (>= 1.0.1)
- Lyo.Authentication.Google (>= 1.0.1)
- Lyo.Authentication.Keycloak (>= 1.0.1)
- Lyo.Authentication.OpenIdConnect (>= 1.0.1)
- Lyo.Authentication.Postgres (>= 1.0.1)
- Lyo.Config (>= 1.0.1)
- Lyo.Config.Postgres (>= 1.0.1)
- Lyo.EntityReference.Models (>= 1.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.