# API-Dokumentation

Source: https://docs.sisk-framework.org/de/docs/extensions/api-documentation.html

Die `Sisk.Documenting`‑Erweiterung ermöglicht es Ihnen, automatisch API‑Dokumentation für Ihre Sisk‑Anwendung zu erzeugen. Sie nutzt Ihre Code‑Struktur und Attribute, um eine umfassende Dokumentations‑Website zu erstellen und unterstützt den Export in das Open‑API‑Format (Swagger).

> [!WARNING]
> Dieses Paket wird als Vorabversion (1.7.0‑rc3) veröffentlicht. Sein Verhalten und die API können sich in zukünftigen Updates ändern.

Installieren Sie das [Sisk.Documenting](https://www.nuget.org/packages/Sisk.Documenting/)‑Paket von NuGet. Um die Dokumentation als HTML‑Seite bereitzustellen, installieren Sie zusätzlich [Sisk.Documenting.Html](https://www.nuget.org/packages/Sisk.Documenting.Html/):

```sh
dotnet add package Sisk.Documenting --prerelease
dotnet add package Sisk.Documenting.Html --prerelease
```

Der Quellcode ist [hier](https://github.com/sisk-http/core/tree/main/extensions/Sisk.Documenting) verfügbar.

Um `Sisk.Documenting` zu verwenden, müssen Sie es im Application‑Builder registrieren und Ihre Route‑Handler mit Dokumentations‑Attributen versehen.

### Registrierung der Dokumentations‑Generierung

Verwenden Sie die Erweiterungsmethode `UseApiDocumentation` auf Ihrem `HttpServerHostContextBuilder`, um die erzeugte API‑Dokumentation über denselben Router bereitzustellen, der Ihre Anwendung bedient.

```csharp
using Sisk.Documenting;
using Sisk.Documenting.Exporters;

// ...

host.UseApiDocumentation(
    context: new ApiGenerationContext()
    {
        ApplicationName = "My Application",
        ApplicationDescription = "Description of my application.",
        ApplicationVersion = "1.0.0"
    },
    routerPath: "/api/docs",
    exporter: new OpenApiExporter() { ServerUrls = ["http://localhost:5555/"] });
```

- **context**: Definiert Metadaten über Ihre Anwendung, wie Name, Beschreibung und Version.
- **routerPath**: Der URL‑Pfad, unter dem die Dokumentations‑Benutzeroberfläche (oder JSON) erreichbar ist.
- **exporter**: Konfiguriert, wie die Dokumentation exportiert wird. Der `OpenApiExporter` aktiviert die Open‑API‑(Swagger‑)Unterstützung.

### Dokumentation von Endpunkten

Sie können Ihre Endpunkte mit den Attributen `[ApiEndpoint]` und `[ApiQueryParameter]` auf Ihren Route‑Handler‑Methoden beschreiben.

### `ApiEndpoint`

Das `[ApiEndpoint]`‑Attribut ermöglicht es Ihnen, eine Beschreibung für den Endpunkt anzugeben.

```csharp
[ApiEndpoint(Description = "Returns a greeting message.")]
public HttpResponse Index(HttpRequest request) { ... }
```

### `ApiQueryParameter`

Das `[ApiQueryParameter]`‑Attribut dokumentiert Abfrage‑String‑Parameter, die der Endpunkt akzeptiert.

```csharp
[ApiQueryParameter(name: "name", IsRequired = false, Description = "The name of the person to greet.", Type = "string")]
public HttpResponse Index(HttpRequest request) { ... }
```

- **name**: Der Name des Abfrage‑Parameters.
- **IsRequired**: Gibt an, ob der Parameter zwingend erforderlich ist.
- **Description**: Eine menschenlesbare Beschreibung des Parameters.
- **Type**: Der erwartete Datentyp (z. B. „string“, „int“).

### `ApiEndpoint`

Annotiert einen Endpunkt mit allgemeinen Informationen.

*   **Name** (string, im Konstruktor erforderlich): Der Name des API‑Endpunkts.
*   **Description** (string): Eine kurze Beschreibung dessen, was der Endpunkt tut.
*   **Group** (string): Ermöglicht das Gruppieren von Endpunkten (z. B. nach Controller oder Modul).
*   **InheritDescriptionFromXmlDocumentation** (bool, Standard: `true`): Wenn `true`, wird versucht, die XML‑Dokumentations‑Zusammenfassung der Methode zu verwenden, falls `Description` nicht gesetzt ist.

### `ApiHeader`

Dokumentiert einen spezifischen HTTP‑Header, den der Endpunkt erwartet oder verwendet.

*   **HeaderName** (string, im Konstruktor erforderlich): Der Schlüssel des Headers (z. B. „Authorization“).
*   **Description** (string): Beschreibt den Zweck des Headers.
*   **IsRequired** (bool): Gibt an, ob der Header für die Anfrage zwingend erforderlich ist.

### `ApiParameter`

Definiert einen generischen Parameter für den Endpunkt, häufig verwendet für Formularfelder oder Body‑Parameter, die nicht durch andere Attribute abgedeckt sind.

*   **Name** (string, im Konstruktor erforderlich): Der Name des Parameters.
*   **TypeName** (string, im Konstruktor erforderlich): Der Datentyp des Parameters (z. B. „string“, „int“).
*   **Description** (string): Eine Beschreibung des Parameters.
*   **IsRequired** (bool): Gibt an, ob der Parameter zwingend erforderlich ist.

### `ApiParameterExample`

Fügt einem dokumentierten Parameter in einer bestimmten Situation einen Beispielwert hinzu. Das Attribut kann mehrfach auf dieselbe Methode angewendet werden.

*   **ParameterName** (string, im Konstruktor erforderlich): Der Name des Parameters, für den das Beispiel gilt.
*   **Title** (string, im Konstruktor erforderlich): Ein Titel, der die durch das Beispiel dargestellte Situation identifiziert.
*   **Description** (string): Wann oder warum das Beispiel gilt.
*   **Example** (string): Der Beispielwert.
*   **ExampleLanguage** (string): Die Sprache, in der der Beispielwert formatiert ist, falls zutreffend.

```csharp
[ApiQueryParameter("status", Type = "string", Description = "Filters orders by status.")]
[ApiParameterExample("status", "Pending orders", Example = "pending")]
[ApiParameterExample("status", "Shipped orders", Example = "shipped", Description = "Orders that left the warehouse.")]
```

### `ApiParametersFrom`

Erzeugt automatisch Parameter‑Dokumentation aus den Eigenschaften einer angegebenen Klasse oder eines Typs.

*   **Type** (Type, im Konstruktor erforderlich): Der Klassen‑`Type`, aus dem die Eigenschaften reflektiert werden sollen.

### `ApiPathParameter`

Dokumentiert eine Pfad‑Variable (z. B. in `/users/{id}`).

*   **Name** (string, im Konstruktor erforderlich): Der Name des Pfad‑Parameters.
*   **Description** (string): Beschreibt, was der Parameter repräsentiert.
*   **Type** (string): Der erwartete Datentyp.

### `ApiQueryParameter`

Dokumentiert einen Abfrage‑String‑Parameter (z. B. `?page=1`).

*   **Name** (string, im Konstruktor erforderlich): Der Schlüssel des Abfrage‑Parameters.
*   **Description** (string): Beschreibt den Parameter.
*   **Type** (string): Der erwartete Datentyp.
*   **IsRequired** (bool): Gibt an, ob der Abfrage‑Parameter vorhanden sein muss.

### `ApiRequest`

Beschreibt den erwarteten Request‑Body.

*   **Description** (string, im Konstruktor erforderlich): Eine Beschreibung des Request‑Bodies.
*   **Example** (string): Ein roher String, der ein Beispiel des Request‑Bodies enthält.
*   **ExampleLanguage** (string): Die Sprache des Beispiels (z. B. „json“, „xml“).
*   **PayloadType** (Type): Falls gesetzt, werden Beispiel und Schema automatisch aus diesem Typ generiert, sofern die konfigurierten Kontext‑Handler dies unterstützen.

### `ApiResponse`

Beschreibt eine mögliche Antwort des Endpunkts.

*   **StatusCode** (HttpStatusCode, im Konstruktor erforderlich): Der zurückgegebene HTTP‑Statuscode (z. B. `HttpStatusCode.OK`).
*   **Description** (string): Beschreibt die Bedingung für diese Antwort.
*   **Example** (string): Ein roher String, der ein Beispiel des Antwort‑Bodies enthält.
*   **ExampleLanguage** (string): Die Sprache des Beispiels.
*   **PayloadType** (Type): Falls gesetzt, werden Beispiel und Schema automatisch aus diesem Typ generiert, sofern die konfigurierten Kontext‑Handler dies unterstützen.

## Type Handlers

Typ‑Handler sind dafür verantwortlich, Ihre .NET‑Typen (Klassen, Enums usw.) in Dokumentations‑Beispiele zu konvertieren. Das ist besonders nützlich, um automatische Request‑ und Response‑Body‑Beispiele basierend auf Ihren Datenmodellen zu erzeugen.

Diese Handler werden innerhalb des `ApiGenerationContext` konfiguriert.

```csharp
using Sisk.Documenting.Content;

var context = new ApiGenerationContext()
{
    // ...
    BodyExampleTypeHandler = new JsonContentTypeHandler(),
    ParameterExampleTypeHandler = new JsonContentTypeHandler(),
    ContentSchemaTypeHandler = new JsonContentTypeHandler()
};
```

### JsonContentTypeHandler

Der `JsonContentTypeHandler` ist ein integrierter Handler, der JSON‑Beispiele, Parameter‑Beispiele und JSON‑Schemas erzeugt. Er implementiert `IExampleBodyTypeHandler`, `IExampleParameterTypeHandler` und `IContentSchemaTypeHandler`.

Er kann mit spezifischen `JsonSerializerOptions` oder `IJsonTypeInfoResolver` angepasst werden, um der Serialisierungs‑Logik Ihrer Anwendung zu entsprechen.

```csharp
var jsonHandler = new JsonContentTypeHandler(new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    WriteIndented = true
});

context.BodyExampleTypeHandler = jsonHandler;
context.ParameterExampleTypeHandler = jsonHandler;
context.ContentSchemaTypeHandler = jsonHandler;
```

### Custom Type Handlers

Sie können eigene Handler implementieren, um andere Formate (wie XML) zu unterstützen oder die Erzeugung von Beispielen anzupassen.

#### IExampleBodyTypeHandler

Implementieren Sie dieses Interface, um Body‑Beispiele für Request‑ und Response‑Typen zu erzeugen.

```csharp
public class XmlExampleTypeHandler : IExampleBodyTypeHandler
{
    public BodyExampleResult? GetBodyExampleForType(Type type)
    {
        // XML-String für den Typ erzeugen
        string xmlContent = MyXmlGenerator.Generate(type);

        return new BodyExampleResult(xmlContent, "xml");
    }
}
```

#### IExampleParameterTypeHandler

Implementieren Sie dieses Interface, um detaillierte Parameter‑Beschreibungen aus einem Typ zu erzeugen (verwendet von `[ApiParametersFrom]`).

```csharp
public class CustomParameterHandler : IExampleParameterTypeHandler
{
    public ParameterExampleResult[] GetParameterExamplesForType(Type type)
    {
        var properties = type.GetProperties();
        var examples = new List<ParameterExampleResult>();

        foreach (var prop in properties)
        {
            examples.Add(new ParameterExampleResult(
                name: prop.Name,
                typeName: prop.PropertyType.Name,
                isRequired: true,
                description: "Generated description"
            ));
        }

        return examples.ToArray();
    }
}
```

## Exporters

Exporter sind dafür verantwortlich, die gesammelten API‑Dokumentations‑Metadaten in ein bestimmtes Format zu konvertieren, das von anderen Tools konsumiert oder dem Benutzer angezeigt werden kann.

### OpenApiExporter

Der standardmäßig bereitgestellte Exporter ist der `OpenApiExporter`, der eine JSON‑Datei gemäß der [OpenAPI Specification 3.0.0](https://spec.openapis.org/oas/v3.0.0) erzeugt.

```csharp
new OpenApiExporter()
{
    OpenApiVersion = "3.0.0",
    ServerUrls = new[] { "http://localhost:5555" },
    Contact = new OpenApiContact()
    {
        Name = "Support",
        Email = "support@example.com",
        Url = "https://example.com/support"
    },
    License = new OpenApiLicense()
    {
        Name = "MIT",
        Url = "https://opensource.org/licenses/MIT"
    },
    TermsOfService = "https://example.com/terms"
}
```

### LlmsApiExporter

Der `LlmsApiExporter` erzeugt ein Klartext‑Dokument im [llms.txt](https://llmstxt.org/)-Stil, das für Sprachmodelle gedacht ist. Sie können den in den Beispielen verwendeten `Hostname` sowie einen `HeaderText` und einen `FooterText` festlegen, die am Anfang bzw. Ende des Dokuments geschrieben werden:

```csharp
new LlmsApiExporter(
    hostname: "https://api.example.com",
    headerText: "Public API of the Example service.",
    footerText: "Contact support@example.com for an API key.")
```

### Creating a Custom Exporter

Sie können Ihren eigenen Exporter erstellen, indem Sie das Interface `IApiDocumentationExporter` implementieren. Damit können Sie Dokumentation in Formaten wie Markdown, HTML, Postman Collection oder einem anderen benutzerdefinierten Format ausgeben.

Das Interface verlangt die Implementierung einer einzigen Methode: `ExportDocumentationContent`.

```csharp
using Sisk.Core.Http;
using Sisk.Documenting;

public class MyCustomExporter : IApiDocumentationExporter
{
    public HttpContent ExportDocumentationContent(ApiDocumentation documentation)
    {
        // 1. Verarbeite das Dokumentationsobjekt
        var sb = new StringBuilder();
        sb.AppendLine($"# {documentation.ApplicationName}");

        foreach(var endpoint in documentation.Endpoints)
        {
            sb.AppendLine($"## {endpoint.Method} {endpoint.Path}");
            sb.AppendLine(endpoint.Description);
        }

        // 2. Gib den Inhalt als HttpContent zurück
        return new StringContent(sb.ToString(), Encoding.UTF8, "text/markdown");
    }
}
```

Dann verwenden Sie ihn einfach in Ihrer Konfiguration:

```csharp
host.UseApiDocumentation(
    // ...
    exporter: new MyCustomExporter()
);
```

### Full Example

Unten finden Sie ein vollständiges Beispiel, das zeigt, wie `Sisk.Documenting` eingerichtet und ein einfacher Controller dokumentiert wird.

```csharp
using Sisk.Core.Entity;
using Sisk.Core.Http;
using Sisk.Core.Routing;
using Sisk.Documenting;
using Sisk.Documenting.Annotations;
using Sisk.Documenting.Exporters;

using var host = HttpServer.CreateBuilder(5555)
    .UseCors(CrossOriginResourceSharingHeaders.CreatePublicContext())
    .UseApiDocumentation(
        context: new ApiGenerationContext()
        {
            ApplicationName = "My application",
            ApplicationDescription = "It greets someone."
        },
        routerPath: "/api/docs",
        exporter: new OpenApiExporter() { ServerUrls = ["http://localhost:5555/"] })
    .UseRouter(router =>
    {
        router.MapInstance(new MyController());
    })
    .Build();

await host.StartAsync();

class MyController
{
    [RouteGet]
    [ApiEndpoint(Description = "Returns a greeting message.")]
    [ApiQueryParameter(name: "name", IsRequired = false, Description = "The name of the person to greet.", Type = "string")]
    public HttpResponse Index(HttpRequest request)
    {
        string? name = request.Query["name"].MaybeNullOrEmpty() ?? "world";
        return new HttpResponse($"Hello, {name}!");
    }
}
```

In diesem Beispiel liefert das Aufrufen von `/api/docs` die erzeugte Dokumentation für die API „My application“ und beschreibt den `GET /`‑Endpunkt sowie dessen `name`‑Parameter.
