Drücke "Enter", um den Text zu überspringen.

Api-Gruppierungen in Swashbuckle umbenennen

Beim Programmieren öffentlicher Web-APIs kommt man an einer ordentlichen API-Dokumentation nicht vorbei. Im Umfeld von ASP.NET Core gibt es hier mehrere Standardlösungen, so dass sich im Allgemeinen die Erstellung einer einfachen Dokumentation recht einfach gestaltet. Eine der bekannteren Lösungen, die auch auf Microsoft Docs gezeigt wird, ist Swashbuckle. Diese erstellt aus Quellcode und XML-Kommentaren eine im Projekt aufrufbare und durchaus brauchbare Dokumentation. Es nutzt hierfür das Framework Swagger, indem für dieses eine passende beschreibende json-Datei erstellt wird.

Das Problem: Umbenennen von API-Gruppen (Controller)

Nun kennt man als Programmierer das Problem: Oftmals reicht an irgendeinem Punkt die Standardkonfiguration nicht mehr aus und an irgendeiner Stelle muss doch etwas anders gemacht werden. Sehr schnell – manchmal auch weniger schnell nach einigen Stunden Gugeln – fällt dann oft der Satz „Ich kann doch nicht der einzige mit diesem Problem sein“. Ungeachtet der Fülle an Informationen des Internets ist man das offenbar manchmal zwar doch, in diesem speziellen Fall gibt es allerdings bereits Mittel und Wege, das Problem zu lösen.

Was noch fehlte (Vielleicht fehlten auch nur mir die korrekten Begriffe für die Google-Suche) war allerdings eine Anleitung für genau dieses Problem. Es gab nur Hinweise in die korrekte Richtung.

Standardverhalten für API-Gruppen

Zunächst muss man verstehen, wie Swashbuckle standardmäßig Gruppen von API-Aufrufen zusammenstellt.

Diese Trennung funktioniert ganz einfach auf Basis von Controllern. Jede Controller-Klasse, die in der ASP.NET Core Anwendung erstellt wurde, wird als eine Gruppe betrachtet. Als Überschrift für diese Gruppe wird dann der Name des jeweiligen Controllers verwendet. Das kann immer dann problematisch werden, wenn sich Controller-Namen wiederholen oder nicht eindeutig unterscheidbar sind. Beispielsweise weil Teile der Information zum Controller sich bereits im Namespace des Controllers befinden.

Ein Beispiel: In einer von mir mitbetreuten Anwendung lassen sich die Interessen von Kunden an Terminen in den Schulferien verwalten. Folgerichtig gibt es im Namespace „Kundenverwaltung.Interessen“ einen FerienController. Die Actions in folgendem FerienController würden dann beispielsweise von Swashbuckle wie folgt dargestellt:

Beispiel für einen von Swashbuckle dokumentierten Controller
Darstellung des Controllers in der API-Dokumenation

ApiExplorerSettings-Attribut to the rescue!

Vorangegangenes Beispiel verdeutlicht recht gut das Problem mit dieser Bezeichnung der Gruppe: Man weiß anhand der API grob, dass es um Ferien geht, mehr aber auch nicht. Weitergehende Infos lassen sich höchstens noch aus den jeweiligen URLs der Web-API ablesen. Schöner wäre es natürlich, wenn man die Überschrift „Ferien“ entsprechend anpassen könnte.

Relativ schnell bin ich hier auf das ApiExplorerSettings-Attribut gestoßen, welches genau dieses Problem der Gruppenbenennung addressieren soll. Nachdem ich flink meinen Controller mit diesem Attribut dekoriert hatte, konnte ich sehen, dass ich nichts mehr sah: Der Controller verschwand komplett aus der API-Dokumentation.

[Route("Kundenverwaltung/Interessen/Ferien")]
[ApiController]
[ApiExplorerSettings(GroupName = "Kundenverwaltung > Interessen > Ferien")]
public class FerienController : Controller { /* ... */ }

Nach weiterer Recherche wurde klar, dass mir eine weitere Standardeinstellung einen strich durch die Rechnung gemacht hatte. Laut Swashbuckle-Dokumentation wird standardmäßig der GroupName verwendet, um die Actions auf verschiedene Dokumentationsseiten zu verteilen.

Anpassung der Swashbuckle-Konfiguration

StackOverflow und eine dort verlinkte GitHub-Issue zeigten, dass noch zwei Dinge in der Swashbuckle-Konfiguration angepasst werden müssen, um das tatsächlich gewünschte Ergebnis zu erhalten.

  1. Swashbuckle muss die mit dem ApiExplorerSettings dekorierten Controller mit in die gewünschte Dokumentationsseite einbinden.
  2. Swashbuckle muss den dort hinterlegten Gruppennamen als Überschrift für die API-Gruppe in der Dokumentation verwenden.

Die vorgeschlagene Lösung auf GitHub ist indes noch nicht die absolute Lösung des Problems. Implementiert man diese, so werden die Gruppennamen zwar basierend auf dem Attribut vergeben, jedoch verschwinden dann alle Controller, die nicht mit dem Attribut dekoriert wurden. Das wollte ich vermeiden, da sonst jeder im Projekt gezwungen wäre, dieses Attribut immer zu verwenden. Daher muss man für diesen Fall eine Zwischenlösung finden.

Für das erste Problem gibt es in den Optionen des Swagger-Generators die Option DocInclusionPredicate. Anhand dieser lässt sich genau steuern, welche Actions im konfigurierten Dokument eingebunden werden sollen. Hier habe ich schlicht beide Bedingungen mit einem ODER verknüpft hinterlegt: Der Gruppenname ist vorhanden oder der ControllerName ist gefüllt.

Ebenfalls eine Option gibt es für Problem Numero zwei: TagActionsBy bestimmt, wie die Gruppennamen vergeben werden sollen. Hier habe ich dann bevorzugt den Gruppennamen aus dem ApiExplorerSettings-Attribut und als Fallback den Controller-Namen zurückgegeben.

Die schlussendliche Konfiguration für den Swagger-Generator sah also so aus:

public void AddSwagger(IServiceCollection services)
{
    services.AddSwaggerGen(options =>
    {
        options.SwaggerDoc("versionXYZ", "Beschreibung");
        options.DocInclusionPredicate(WirdControllerDokumentiert);
        options.TagActionsBy(BestimmeApiGruppenNamen);
    });
}

private bool WirdControllerDokumentiert(string dokumentationsName, ApiDescription api)
    => !string.IsNullOrWhitespace(api.GroupName)
        || !string.IsNullOrWhitespace(BestimmeControllerNamen(api));

private IList<string> BestimmeApiGruppenNamen(ApiDecription api)
    => !string.IsNullOrWhitespace(api.GroupName)
        ? new List<string> { api.GroupName }
        : new List<string> { BestimmeControllerNamen(api) };

private string BestimmeControllerNamen(ApiDescription api)
    => ((ControllerActionDescriptor)api.ActionDescriptor).ControllerName;

Ergebnis der Einstellungen

Nach diesen Einstellungen stimmte dann das Ergebnis genau mit der Wunschvorstellung überein:

Anzeige von API-Gruppen in der Swashbuckle-Dokumentation

Quellen

Software

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.