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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Lyo.Config.Api" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Lyo.Config.Api" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="Lyo.Config.Api" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Lyo.Config.Api --version 1.0.1
                    
#r "nuget: Lyo.Config.Api, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Lyo.Config.Api@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Lyo.Config.Api&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=Lyo.Config.Api&version=1.0.1
                    
Install as a Cake Tool

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 to MapConfigApiEndpoints, the middleware will not match it — /api/config is the hard-coded path check.
  • When ConfigApiSecurity.RequireApiKey == false, the middleware short-circuits to _next without inspecting headers. Toggling RequireApiKey to true requires the host to configure a non-empty ApiKey; otherwise matching requests get 500 Internal Server Error with { "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> or Authorization: Bearer <value> (other schemes are rejected). Comparison uses CryptographicOperations.FixedTimeEquals over UTF-8 bytes; missing / empty / mismatching credentials produce 401 Unauthorized with 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: same ETag / 304 behaviour, no body on 200.
  • POST: same body as GET when 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 for Lyo.Config.Postgres.
  • ConfigApiHosting: optional PollIntervalAdvisoryMilliseconds (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

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.Cryptography 2.6.2 — (transitive, third-party, netstandard2.0)
  • EasyCompressor 2.1.0 — (transitive, third-party)
  • Konscious.Security.Cryptography.Argon2 1.3.1 — (transitive, third-party)
  • Microsoft.AspNetCore.Authorization 10.0.5 — (transitive, microsoft)
  • Microsoft.AspNetCore.Http.Abstractions 2.* — (transitive, microsoft)
  • Microsoft.AspNetCore.OpenApi 10.0.5 — (transitive, microsoft)
  • Microsoft.Bcl.AsyncInterfaces 10.0.5 — (transitive, microsoft, netstandard2.0)
  • Microsoft.EntityFrameworkCore 10.0.5 — (transitive, microsoft)
  • Microsoft.EntityFrameworkCore.Analyzers 10.0.5 — (transitive, microsoft)
  • Microsoft.EntityFrameworkCore.Design 10.0.5 — (transitive, microsoft)
  • Microsoft.EntityFrameworkCore.Relational 10.0.5 — (transitive, microsoft)
  • Microsoft.Extensions.Caching.Memory 10.0.5 — (transitive, microsoft)
  • Microsoft.Extensions.Configuration.Binder 10.0.5 — (transitive, microsoft)
  • Microsoft.Extensions.DependencyInjection 10.0.5 — (transitive, microsoft)
  • Microsoft.Extensions.DependencyInjection.Abstractions 10.0.5 — (transitive, microsoft, net10.0, netstandard2.0)
  • Microsoft.Extensions.Hosting.Abstractions 10.0.5 — (transitive, microsoft)
  • Microsoft.Extensions.Logging.Abstractions 10.0.5 — (transitive, microsoft)
  • Microsoft.Extensions.Options 10.0.5 — (transitive, microsoft)
  • Microsoft.Extensions.Options.ConfigurationExtensions 10.0.5 — (transitive, microsoft)
  • Npgsql.EntityFrameworkCore.PostgreSQL 10.0.3 — (transitive, third-party)
  • SmartFormat.NET 3.6.1 — (transitive, third-party)
  • System.Buffers 4.6.1 — (transitive, microsoft, netstandard2.0)
  • System.ComponentModel.Annotations 5.0.0 — (transitive, microsoft)
  • System.IO.Hashing 10.0.5 — (transitive, microsoft, net10.0)
  • System.Memory 4.6.3 — (transitive, microsoft, netstandard2.0)
  • System.Text.Json 10.0.5 — (transitive, microsoft, netstandard2.0)
  • System.Threading.Tasks.Extensions 4.6.3 — (transitive, microsoft, netstandard2.0)
Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 0 8/18/2026
1.0.0 55 8/16/2026