Zum Inhalt

HTTP-APIs

Endpunkte sind Minimal-APIs, die einen Request an den Dispatcher geben. MapCoworkeeApi legt die Routengruppe an, damit Konventionen der Pakete (etwa Response-Filter) jedes Modul erreichen.

var products = app.MapCoworkeeApi("/api/v1/products").WithTags("Products").RequireAuthorization();
products.MapGet("/{id:guid}", (Guid id, IDispatcher d, CancellationToken ct) => d.SendAsync(new GetProductByIdQuery(id), ct).ToHttpResult());
products.MapPost("/", (AddEditProductRequest body, IDispatcher d, CancellationToken ct) => d.SendAsync(new AddEditProductCommand(null, body), ct).ToHttpResult());

Dienste mit vielen Endpunkten können sich das Mapping sparen: Anwendungsdienste werden per Konvention bereitgestellt und bekommen einen generierten Blazor-Client.

Aus Results werden Antworten

Result Antwort
Result.Success() 204 No Content
Result<T> erfolgreich 200 OK mit dem Wert
Error.Validation 400 Problem Details mit einem errors-Wörterbuch pro Feld
Error.Unauthorized / Forbidden / NotFound / Conflict 401 / 403 / 404 / 409 Problem Details
Error.Unexpected 500 Problem Details

Jede Problem-Details-Antwort enthält den code des Fehlers, damit Clients auf catalog.brand_name_taken reagieren können, statt Text auszuwerten.

Konventionen für alle API-Gruppen

Ein Paket oder die App kann jeder mit MapCoworkeeApi angelegten Gruppe etwas hinzufügen:

services.Configure<CoworkeeApiOptions>(options => options.AddConvention(group => group.AddEndpointFilter<MyFilter>()));

Die API absichern

Die API prüft die Bearer-Tokens des Coworkee-Auth-Servers:

MyApp.Api/MyAppApiModule.cs
context.Services.AddCoworkeeApiAuthentication(context.Configuration, audience: "myapp_api");

Authority und Audience kommen aus Coworkee:ApiAuth; der AppHost setzt sie. Browser halten diese Tokens nie: Das übernimmt der BFF, siehe Anmeldung.

OpenAPI

UseCoworkee liefert in der Umgebung Development das OpenAPI-Dokument (/openapi/v1.json) und die Swagger-Oberfläche aus, sonst nur mit Coworkee:OpenApi:Enabled=true. Tags und Namen kommen aus den Endpunktdefinitionen (WithTags, WithName).

Das Dokument bleibt anonym lesbar (SDK-Generatoren und Snapshot-Tests lesen es) und deklariert ein Bearer-Schema, sodass der Authorize-Knopf direkt gegen die API funktioniert. Die Swagger-Oberfläche (/swagger) braucht einen angemeldeten Benutzer mit ApiDocs.View. Das BFF leitet /swagger und /openapi weiter: /swagger auf der Adresse der Web-App öffnen (Menüeintrag „API“) meldet zuerst an, danach läuft jede Anfrage als Sie, Token und CSRF-Header kommen automatisch dazu. Ein Dunkelmodus-Schalter folgt der Systemeinstellung.

Versionen

Routen tragen die Version im Pfad. Ein Präfix /api/v{n}/… in MapCoworkeeApi ordnet die Gruppe der Version n zu (Asp.Versioning-Metadaten); Version 1 deklariert AddCoworkee, weitere Versionen das Modul, das sie mitbringt:

public override void ConfigureServices(ModuleServiceContext context) => context.Services.AddCoworkeeApiVersion(2);

public void ConfigureApplication(WebApplication app)
{
    app.MapCoworkeeApi("/api/v1/products").MapGet("/", ...);
    app.MapCoworkeeApi("/api/v2/products").MapGet("/", ...);
}

Jede Version bekommt ein eigenes Dokument, /openapi/v2.json, und einen Eintrag in der Versionsauswahl der Swagger-Oberfläche. /openapi/v1.json enthält weiterhin alle Endpunkte ohne Version (einfaches MapGroup, MapGet) und ändert sich durch die Versionierung nicht; v2 listet nur v2-Endpunkte. Die Pfade bleiben wörtlich, kein Dokument hat einen Parameter {version}.

Rate Limiting

AddCoworkee registriert den Rate Limiter von ASP.NET Core, UseCoworkee führt ihn nach der Authentifizierung aus. Die Grenzen sind feste Zeitfenster pro angemeldetem Benutzer, für anonyme Aufrufer pro IP-Adresse; eine abgewiesene Anfrage bekommt 429 als Problem Details mit dem Code rate_limited und einem Retry-After-Header.

Policy Standard Gilt für
auth 60 pro Minute Anmelde-, Registrierungs- und Passwortseiten des Auth-Servers
ai 30 pro Minute /api/v1/ai/* und /mcp
upload 120 pro Minute nichts Eingebautes; für eigene Upload-Endpunkte
global aus jede Anfrage, sobald konfiguriert
uploads.MapPost("/", ...).RequireCoworkeeRateLimit(CoworkeeRateLimitOptions.Upload);
appsettings.json
{
  "Coworkee": {
    "RateLimiting": {
      "Enabled": true,
      "Global": { "PermitLimit": 1000, "Window": "00:01:00" },
      "Policies": { "ai": { "PermitLimit": 10 }, "reports": { "PermitLimit": 5, "Window": "00:10:00" } }
    }
  }
}

Die Konfiguration ändert die eingebauten Policies oder fügt neue hinzu. Enabled: false lässt die Middleware weg. Hinter einem Proxy die Client-Adresse weiterreichen (UseForwardedHeaders), sonst teilen sich alle anonymen Aufrufer ein Zeitfenster. Der Token-Endpunkt ist nicht begrenzt: Hinter dem BFF kommen alle Refreshes von einer Adresse.