Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Lesedauer 14 Min.

OpenAPI im Praxiseinsatz

Die Dokumentation von Schnittstellen ist elementarer Bestandteil eines jeden größeren Softwareprojekts – und dank der OpenAPI-Spezifikation automatisiert durchführbar.
© dotnetpro
Cloud-Umgebungen und Microservices haben den Aufbau von Diensten und Schnittstellen in den letzten  zehn Jahren grundsätzlich verändert. Statt der früher üblichen direkten Verknüpfung einzelner Anwendungskomponenten zu ­einem großen Monolithen besitzen nun mehrere Komponenten eigene Schnittstellen und Kommunikationswege.Die dominierende Variante im Zuge dieser Schnittstellen sind Web APIs. Gerade durch die vermehrte Kommunikation in verteilten Cloud-Systemen oder mobilen beziehungsweise Webapplikationen findet man entsprechende Schnittstellen in allen möglichen Anwendungen.Hauptvorteil dieser Schnittstellen ist natürlich die vielsei­tige Verwendbarkeit und Eigenständigkeit. Zudem dienen diese nicht nur der weiteren Abstraktion der Geschäftslogik zwischen Service und Client, sondern tragen dazu bei, Code zu reduzieren und so die Testbarkeit und Wartbarkeit zu steigern sowie Fehlerquellen drastisch zu reduzieren.

Warum braucht es eine Dokumentation?

Hierbei stellt sich jedoch die Herausforderung der korrekten Implementierung einer Schnittstelle. Meist ist ein bestimmter Personenkreis für die Umsetzung der serverseitigen Schnittstelle und die Implementierung der Geschäftslogik zuständig. Auf der anderen Seite steht dann zum Beispiel ein Team, das die Frontend-Anwendung oder andere Tools umsetzt und diese entsprechend integrieren muss – und dies im besten Fall in einem externen Unternehmen.Da ist der Aufwand, um eine entsprechende Schnittstellendefinition zu erstellen und zu warten, natürlich nicht unerheblich. Selbst wenn hier ein großer Aufwand betrieben wird und man die Dokumentation intern verifizieren lässt, dauert es sicher nicht lange, bis Missverständnisse auftreten. Aus der Praxis heraus sind oft einfachste Fehler wie ein vergessener Parameter oder eine beim Copy-and-paste-Vorgang vergessene Aktualisierung des Datentyps schon Ursache für Stirnrunzeln auf beiden Seiten der Schnittstelle.Es ist also zwingend notwendig, zu jedem Zeitpunkt die Schnittstelle korrekt und nach dem tatsächlichen Stand beschreiben zu können.

Die Dokumentation passt – wie geht es weiter?

Angenommen, das Team, das die Schnittstelle baut, stellt ­eine vollständig korrekte und mit jedem Release aktualisierte Version bereit. Wie geht nun die Gegenseite damit um?Wenn man beispielsweise einmal im Monat eine PDF-Datei mit tabellarischen Informationen über Endpunkte bekommt, bedeutet dies vor allem eines: Handarbeit. Und genau hier schleichen sich die größten und zeitaufwendigsten Fehler in der Implementierung einer Schnittstelle ein. Neben der Möglichkeit, dass die Spezifikation nicht zu der Anwendung passt, ist auf der Gegenseite ebenfalls die gleiche Fehlerquelle gegeben. Realistisch betrachtet ist die Fehlersuche daher bei jeder Ungereimtheit auf beiden Seiten durchzuführen. Dabei wird schnell klar, dass dies kein sonderlich produktiver und effizienter Prozess ist.

Was ist also die Lösung?

Schnittstellendefinitionen wurden jahrzehntelang als ein vertragliches Schriftstück angesehen. Dieser bürokratische Ansatz führt genau zu solchen Definitionen, wie wir sie heute in großer Menge vorliegen haben.Im Jahr 2011 wurde im Rahmen des Open-Source-Projekts namens Swagger, das diverse Tools für die Umsetzung und das Testing von Web APIs (darunter REST-like, RESTful oder REST-APIs) umfasste, ein Projekt mit der Bezeichnung Swagger API gestartet. Hierbei wurde nach einem Weg gesucht, sowohl technische Schnittstellen eindeutiger zu beschreiben als auch später solche Spezifikationen aus vorhandenem Code generieren zu können. Kurze Zeit später folgten diverse Code-Generatoren, welche anhand einer entsprechenden Swagger-API-Spezifikation auch passenden Client-Code in diversen Entwicklungsumgebungen bereitstellen konnten. Wer möchte, kann dies in etwa mit dem damals verbreiteten WSDL-Format für SOAP-Schnittstellen vergleichen.Mit den Jahren wurde Swagger immer beliebter, und ab circa Mitte der 2010er-Jahre bildete es bereits eine feste Instanz bei der Umsetzung von Web APIs.Um diese Zeit wurde das vorhandene Swagger API in die von der Linux Foundation unterstützte OpenAPI-Initiative übernommen. Dadurch wurde die Schnittstellenspezifikation für Web APIs zu einem offenen Standard auserkoren.

Was genau dokumentiert OpenAPI/Swagger?

Dreh- und Angelpunkt dieser Dokumentation ist schlicht ein vorgegebenes JSON-Schema. Die Schnittstellen, Datenmodelle, Endpunkte oder auch akzeptierte Authentifizierungsmechanismen werden in einer JSON-Datei beschrieben und kommentiert (Bild 1). Hierbei werden einzelne Infos und Beschreibungen zu der jeweiligen Schnittstelle im Allgemeinen sowie Hilfestellungen und weiterführende Links dokumentiert. Dies ist insbesondere dann interessant, wenn man eine Schnittstelle öffentlich zugänglich machen will.
Struktureiner beispielhaften ­Swagger-JSON-Datei(Bild 1) © Autor
Weiterhin können Transportschemas definiert werden, die festlegen, ob die eigene Schnittstelle ausschließlich HTTPS nutzt oder auch eine Verbindung via HTTP aufgebaut werden kann.Die Hauptfunktionalität ist die Beschreibung der einzelnen Aufrufpfade und deren HTTP-spezifischer Parameter. Zu jedem Pfad, wie zum Beispiel /api/persons, können einzelne Methoden wie eben GET definiert werden. Jeder Aufruf und jeder Parameter kann entsprechende Beschreibungen, Kommentare und auch einen eindeutigen Namen erhalten. Anhand der Beschreibung und des Kommentars können außenstehende Entwickelnde so relativ einfach identifizieren, was diese Aktion ausführt beziehungsweise welcher Parameter auf welche Weise verwendet wird.Jeder Aufrufparameter kann hierbei den Namen, den Datentyp (oder das Datenmodell) und dessen HTTP-spezifische Art (Query-Parameter in URL, Form-Data, Header, Request-Body et cetera) spezifizieren.Mit diesen Informationen sind der Weg und die Anforderungen des Aufrufs entsprechend beschrieben. Genauso können auch die möglichen Rückgabewerte spezifiziert und beschrieben werden, welche Inhalts­typen zu produzieren sind (zum Beispiel XML, JSON oder mehrere). Ebenso kann für jeden Response-Code eine Definition des Rückgabewerts definiert werden.Im Fall eines erfolgreichen Aufrufs wird normalerweise ein Datenmodell mitgeliefert. Beim Auftreten von Fehlern (zum Beispiel 404 oder 500) kann beschrieben werden, welche Daten in diesen Fällen zurückgeliefert werden.Ein weiteres Feature der Aktionsbeschreibung sind die Sicherheitsmaßnahmen. Hier kann denjenigen Aktionen, die zum Beispiel eine Authentifizierung benötigen, das entsprechende Sicherheitsschema zugeordnet werden. In der Basis-Spezifikation werden sämtliche akzeptierten Sicherheits-Schemas (zum Beispiel Basic Auth, Bearer Token, API-Keys) definiert. Dies kann auch ein gänzlich individuelles Sicherheitsschema sein (wie zum Beispiel, dass im Header ein Key MEIN_AUTH_CODE erwartet wird).Ebenfalls werden sämtliche verwendeten Datenmodelle, ob sie nun als Abfrageparameter oder Rückgabewert dienen, als typensicheres Modell spezifiziert. Selbst Validierungsinformationen (zum Beispiel zwingend erforderlich et cetera) können beigefügt werden.Diese Features bilden nahezu alle erdenklichen Szenarien in einem Web API ab, die dokumentiert werden müssen.Nun ist es natürlich so, dass wohl niemand eine solche Spezifikation manuell erstellen möchte. Glücklicherweise kann in vielen Entwicklungs-Frameworks, darunter auch .NET beziehungsweise ASP.NET, eine solche Dokumentation automatisiert generiert werden.

SwaggerUI für schnelle Tests

Die entsprechende JSON-Datei vorliegen zu haben ist aber erst der erste Schritt. Auch hier möchte kaum jemand eine JSON-Datei durchgehen und erfahren, welche Aktionen im Einzelnen welche Parameter benötigen – das wäre ein nicht wirklich eleganter und benutzerfreundlicher Weg. Aus diesem Grund existiert Swagger UI, de facto mittler­weile die Standard-Benutzeroberfläche für OpenAPI/Swagger-Spezifikationen.Dies ist eine kleine Weboberfläche, welche dynamisch aus einer entsprechenden JSON-Datei eine bedienbare Oberfläche für das Ausführen der Requests und einen strukturierten Aufbau über die Aktionen und Datenmodelle gibt (Bild 2).
Das Swagger UImit einem Beispiel-Server(Bild 2) © Autor
Insbesondere während der Entwicklungsphase ist dies eine beliebte Arbeitshilfe. Wenn die Swagger-Spezifikation aus dem Code automatisiert generiert wird und Änderungen live durchgeführt werden, können diese aus dem Browser heraus gegengeprüft werden. Man spart sich auf diese Weise also eine clientsei­tige Implementierung.Eine Alternative in der späteren Entwicklungs- und Testphase wäre das Einspielen der OpenAPI-Spezifikation in ein dediziertes Tool, wie zum Beispiel Postman (Bild 3). Hier können wesentlich detailliertere Analysen der Requests durchgeführt werden. Gerade für Integrationstests bietet sich ein solcher Schritt an.
Postmanfür clientseitiges Testing(Bild 3) © Autor

Ein ASP.NET-Web-API-Projekt aufbauen

Nutzen wir für unser Beispiel ein ASP.NET Web API. Hier kann in Visual Studio ein entsprechendes Projekt angelegt werden. Alle unsere API-Aktionen werden in dem entsprechenden Controller zusammengefasst. Für einen Controller mit dem Namen CustomersController sieht dies wie folgt aus.
[Route("Customers")] 
  public class CustomersControllerV1 : Controller 
  { 
    // GET:Customers 
    [HttpGet] 
    public IEnumerable<string> Get() 
    { 
      return new string[] { "value1", "value2" }; 
    } 
  } 
In diesem vereinfachten Beispiel wird die Route Customers definiert und im Fall eines GET-Aufrufs auf diese Route die vorliegende Aktion ausgeführt. Diese liefert hier statisch die Werte value1 und value2 als String-Array zurück.Würden wir nun aus diesem vorliegenden Code eine OpenAPI-Spezifikation erstellen, hätten wir lediglich die Information, dass es eine Aktion /Customers gibt, die via HTTP-GET aufgerufen werden kann und ein String-Array zurückliefert. Wir hätten noch keine Information über die Verwendung, irgendwelche Beschreibungen oder Ähnliches.Bevor wir das Thema Kommentare und Beschreibungen im Konkreten beleuchten, schauen wir uns die Einbindung von Swagger in ein ASP.NET-Projekt an.

Swagger plus  ASP.NET Web API

Nachdem unser erster Controller erstellt wurde, konfigurieren wir unsere ASP.NET-Anwendung, sodass diese automatisierte OpenAPI-Spezifikationen generiert sowie ein Swagger UI anbietet. Dies hilft uns, live verfolgen zu können, welche Änderungen wir durchgeführt haben und ob sie live testbar im Browser sind.Hierzu wird ein NuGet-Paket benötigt, das den Namen Swashbuckle.AspNetCore trägt und drei zentrale Komponenten vereint. Zum einem besitzt es das Swagger/OpenAPI-Objektmodell, das für die Spezifikation benötigt wird. Die zweite Komponente ist die Magie hinter dem Paket – nämlich die Middleware, welche automatisiert die Swagger-Spezifikation aus den vorliegenden ASP.NET-Core-Controllern generiert, sowie das Swagger UI, das die Verwendung des Swagger API visuell als Weboberfläche zur Verfügung stellt.Nachdem das Paket installiert wurde, sieht eine vereinfachte Konfiguration wie folgt aus: Man ergänzt hierzu in der Program.cs die eigenen Services mit dem Swagger-Generator. Dies hat nach dem Hinzufügen der Controller zu geschehen, was mit dem Aufruf AddControllers() erfolgt.
builder.Services.AddControllers(); 
builder.Services.AddEndpointsApiExplorer(); 
builder.Services.AddSwaggerGen(); 
Mit dem ApiExplorer sowie dem SwaggerGen kann die Komponente nun sämtliche Aktionen und Parameter auslesen und zu einer OpenAPI-Spezifikation verarbeiten.Um an diese OpenAPI-Spezifikation gelangen zu können, muss aber in unserer app-Konfiguration der Endpunkt für Swagger ebenso wie unser Swagger UI verfügbar gemacht werden. Dies geschieht ebenfalls in der Program.cs.
app.UseSwagger(); 
app.UseSwaggerUI(); 
Mit diesen beiden Zeilen kann die Anwendung gestartet werden. Sobald der Endpunkt http/s://localhost:<port>/swagger aufgerufen wird, erhalten wir die entsprechende Swagger-UI-Oberfläche, in der wir den Aufruf für unseren CustomerController sehen können. Die JSON-Datei (die ebenfalls in der Swagger-UI-Oberfläche ersichtlich ist) kann standardmäßig über den URL http/s://localhost<port>/swagger/v1/swagger.json abgerufen werden.Achtung: Überlegen Sie sich genau, ob Sie die Swagger-Spezifikation und/oder das Swagger UI immer aktiv belassen möchten. Falls Sie nur wünschen, dass die Spezifikation als JSON abgerufen werden kann, empfiehlt es sich, entweder über Build-Konstanten (#if Debug) oder über das Anwendungs-Environment (app.Environment.IsDevelopment()) die entsprechenden Verfügbarkeiten zu steuern. Das verhindert, dass in einem produktiven System zu viele Informationen bereitgestellt werden (wenn diese nicht öffentlich sind) beziehungsweise dass ein Test-UI auf einem produktiven System läuft und darüber Abfragen durchgeführt werden können.Es gibt hier unzählige weitere Möglichkeiten zur Konfiguration und Anpassung, wie eine gewünschte OpenAPI-Spezifikation aus unserem Code generiert und bereitgestellt wird. Darauf gehen wir nach dem folgenden Abschnitt ein.

But first: Versionieren

Ein grundsätzliches Thema möchte ich hier im Zuge der Umsetzung von Web APIs anbringen: Versionierung. Dieser Punkt wird oftmals zunächst unterschätzt, und dann wird versucht, ihn im Nachgang zu implementieren.Daher empfehle ich, bevor die erste Zeile Geschäftslogik geschrieben wird, sich mit diesem Thema auseinanderzusetzen und eine Versionierung der APIs vorzusehen. Glücklicherweise übernimmt ASP.NET hier das Gros der Arbeit und Swagger kann darauf reagieren. Also legen wir damit los.an dieser Stelle wird wieder ein Paket benötigt mit dem Namen ASP.NET API Versioning. Nach der Installation dieses Pakets ist es notwendig, diesen Service der ASP.NET-Core-Pipeline bekannt zu machen. Dies geschieht über die Startup-Konfiguration und wird folgendermaßen über den Aufruf services.AddApiVersioning() durchgeführt:
public void ConfigureServices(
    IServiceCollection services) 
{ 
  // Add framework services. 
  services.AddMvc(); 
  services.AddApiVersioning(); 
} 
Nach dieser Konfiguration ist es möglich, über Annotationen der Controller oder der entsprechenden Funktionen und Methoden das Routing zu versionieren. Im besagten Beispiel würde unser CustomersController wie folgt aussehen.
[Route("api/v{version:apiVersion}/Customers")] 
  [ApiVersion("1")] 
public class CustomersControllerV1 : Controller 
{ 
  // GET: api/v1/Customers 
  [HttpGet] 
  public IEnumerable&lt;string&gt; Get() 
  { 
    return new string[] { "value1", "value2" }; 
  } 
} 
Die ApiVersion (in diesem Beispiel Version 1) wurde als Annotation angegeben sowie das entsprechende Routing angepasst. Durch das angepasste Routing ist dieser Controller nun in der Lage, auf einen Aufruf über den URL http/s://localhost: <port>/api/v1/Customers zu reagieren. Somit können sämtliche Clients den korrekt ver­sio­nierten Controller ansprechen. Der Nachteil liegt hier natürlich darin, dass einzelne Funk­tio­nen beziehungsweise gesamte Controller für eine neue Version als Kopie vorliegen müssen. Eventuelle Bugfixes sind deshalb, je nachdem, wie die Architektur umgesetzt worden ist, vielleicht an mehreren Stellen zu beheben. Entwickler sollten sich daher im Klaren darüber sein, ob die Versionierung auf Basis eines Controllers oder auf Basis einzelner Funktionen und Methoden stattfinden soll. Das vorgestellte Versionierungspaket unterstützt zudem kombinierte Möglichkeiten und Fallback-Optionen. Dementsprechend lohnt sich ein Blick in die Projektdokumentation.

OpenAPI/Swagger konfigurieren

Wie bereits erwähnt, möchten wir nun unserer Swagger-Dokumentation zum einem mehr Informationen, zum Beispiel in Form von Beschreibungen, mitliefern sowie auch die soeben umgesetzte Versionierung voll ausnutzen.Vorhin blickten wir auf die Standardkonfiguration mittels des Service AddSwaggerGen(). Dieser kann beliebig erweitert werden und mithilfe des folgenden Codebeispiels auch für die Versionierung angepasst werden.Neben der Versionierung werden wir nun auch die „Magie“ hinter den Beschreibungen einzelner Parameter und Aktionen konfigurieren – die bekannten Dokumentationskommentare, welche seit den Anfängen von .NET eine Dokumentation direkt aus dem Code heraus ermöglichen.Diese Kommentare werden als gesonderte XML-Datei bereitgestellt und können bei der Generierung der Swagger-Dokumentation herangezogen werden. Demnach sieht unsere Service-Konfiguration wie folgt aus:
services.AddSwaggerGen(c =&gt; 
{ 
  c.SwaggerDoc("v1", new Info { 
    Title = "Hello API", Version = "v1" }); 
  c.DocInclusionPredicate((docName, apiDesc) =&gt; 
  { 
    var versions = apiDesc.ControllerAttributes() 
    .OfType&lt;ApiVersionAttribute&gt;() 
    .SelectMany(attr =&gt; attr.Versions); 

    return versions.Any(v =&gt; $"v{
      v.ToString()}" == docName); 
  }); 

  c.OperationFilter&lt;RemoveVersionParameters&gt;(); 
  c.DocumentFilter&lt;SetVersionInPaths&gt;(); 

  //enable xml-comments 
  var basePath = PlatformServices.Default.Application
    .ApplicationBasePath; 
  var xmlPath = Path.Combine(basePath, "MyNewApi.xml"); 
  c.IncludeXmlComments(xmlPath); 
}); 
Wichtig: Hier gibt es mehrere Möglichkeiten, die Dokumentation entsprechend zu versionieren und zusammenzustellen. Teils existieren vorgefertigte NuGet-Pakete, die einen Teil der Aufgaben durchführen. In diesem Beispiel gehen wir aber einen etwas stärker manuell ausgeprägten Weg. Konkret wird hier unsere Version v1 definiert sowie eine Beschreibung Hello API mitgeliefert.Im nächsten Schritt werden über die übergebene Aktion in DocInclusionPredicate diejenigen Aktionen/Controller gefiltert, die eine zuvor registrierte Version als ApiVersionAttribute besitzen.Hierbei wird aber aktuell noch nicht die Version in den entsprechenden URL in der Dokumentation gesetzt. So würde unsere Schnittstellenspezifikation noch nicht das gewünschte Ergebnis liefern. Aus diesem Grund gibt es sogenannte Operation- und DocumentFilter. Dies sind einfache Klassen, die Swashbuckle verwendet, um zu identifizieren, ob diverse Aktionen oder Controller angepasst werden müssen.Der OperationFilter RemoveVersionParameters löscht die API-Version von den einzelnen Aktionen und deren Parametern heraus. Würde dieses nicht geschehen, hätte jede Ak­tion einen URL-Parameter mit dem Namen Version. Wir wollen die Version aber bereits in unserer Definition (zum Beispiel v1) fest integrieren und im Rahmen des Basis-URL definieren. Der entsprechende OperationFilter sieht hier wie folgt aus:
using Swashbuckle.AspNetCore.Swagger; 
using Swashbuckle.AspNetCore.SwaggerGen; 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 

namespace MyNewApi.Swagger 
{ 
  public class RemoveVersionParameters : 
      IOperationFilter 
  { 
    public void Apply(Operation operation, 
        OperationFilterContext context) 
    { 
      // Remove version parameter from all Operations 
      var versionParameter = operation.Parameters
        .Single(p =&gt; p.Name == "version"); 
      operation.Parameters.Remove(versionParameter); 
    } 
  } 
} 
Es wird also jede Operation beziehungsweise Aktion in der Spezifikation entsprechend geprüft und der vorhandene Parameter mit dem Namen version gelöscht.Führen wir nun unser API aus und schauen wir uns dabei die Spezifikation an, dann haben wir an keiner Stelle festgelegt, wo nun die API-Version definiert werden soll. Demzufolge schlagen unsere Aufrufe fehl. Um dies zu umgehen, muss die API-Version in den Pfaden fest hinterlegt werden. Dies geschieht über den DocumentFilter SetVersionInPaths.
using Swashbuckle.AspNetCore.Swagger; 
using Swashbuckle.AspNetCore.SwaggerGen; 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 

namespace MyNewApi.Swagger 
{ 
  public class SetVersionInPaths : IDocumentFilter 
  { 
    public void Apply(SwaggerDocument swaggerDoc, 
        DocumentFilterContext context) 
    { 
      swaggerDoc.Paths = swaggerDoc.Paths 
          .ToDictionary( 
        path =&gt; path.Key.Replace("v{version}", 
          swaggerDoc.Info.Version), 
        path =&gt; path.Value 
      ); 
    } 
  } 
} 
Damit wird nun die betreffende Stelle, die im Pfad aktuell als v{version} (und damit ein ungültiger Pfad) definiert ist, mit der entsprechenden Version des Swagger-Dokumenta­tion ersetzt. Aktuell existiert nur eine SwaggerDoc, die wir im Aufruf AddSwaggerGen definiert haben und der Version v1 zugeordnet haben.Mit dieser Konstellation aus dem Filtern der Controller, die für das SwaggerDoc entsprechende API-Versionen als Parameter beinhalten, sowie der Umsetzung der Parameter in den Pfad funktioniert der Aufruf auf zum Beispiel den ClientController über den gewünschten URL http/s://localhost:<port>/api/v1/Customers.Werden später also Breaking Changes notwendig, legt man eine weitere SwaggerDoc mit der Version v2 an und gibt die entsprechenden Attribute den Controllern, die in der Version 2 zur Verfügung stehen sollen. Hier kann man sich nun entweder dafür entscheiden, ausschließlich die neuen Funktionalitäten mit einem Aufruf über v2 durchzuführen, oder sämtliche unangepassten Controller mit einem zusätzlichen Attribut für die Version v2 versehen.

XML-Kommentare und Rückgabewerte

Um das volle Potenzial aus OpenAPI und Swagger zu nutzen, müssen entsprechende XML-Kommentare verwendet werden, die vielen bereits durch den Umgang mit öffentlichen Schnittstellen bekannt sein sollten.Hierbei werden zum Beispiel für eine Klasse oder Methode/Funktion als Kommentarblock weiterführende Informa­tio­nen geliefert (zum Beispiel eine Beschreibung der Methode oder der einzelnen Parameter), die als XML-Datei beim Build-Vorgang generiert werden. Achtung: Dies muss in den Projekteinstellungen aktiviert werden.Eine Methode, welche zum Beispiel einen neuen Kunden erstellt, sieht wie folgt aus und nutzt hierbei die Möglichkeiten der Code-Kommentierung:
/// &lt;summary&gt; 
/// Creates a new customer. 
/// &lt;/summary&gt; 
/// &lt;remarks&gt; 
/// Creates a simple customer-object with a new id and 
      returns it. 
/// &lt;/remarks&gt; 
/// &lt;param name="name"&gt;Last name of the customer&lt;/param&gt; 
/// &lt;param name="firstName"&gt;First name of the customer
      &lt;/param&gt; 
/// &lt;param name="authenticationToken"&gt;Authentication-
      Token for this request&lt;/param&gt; 
/// &lt;returns&gt;Returns the new customer-object&lt;/returns&gt; 
/// &lt;response code="200"&gt;Returns the new customer-
      object&lt;/response&gt; 
/// &lt;response code="401"&gt;Authentication-Token is not 
      valid&lt;/response&gt; 
[HttpPut] 
public ICustomer Put([FromForm, Required]string name, 
    [FromForm]string firstName, [FromHeader(Name="AUTH" 
    )]string authenticationToken) 
{ 
  if(String.IsNullOrEmpty(authenticationToken)) 
    this.Unauthorized(); 

  return new Customer() { 
    Id = Guid.NewGuid(), 
    Name = name, 
    FirstName = firstName 
  };      
} 
Dieser PUT-Aufruf nimmt als Form-Data die Parameter name und firstName entgegen. Beispielhaft wird ein Header-Parameter benötigt, der den Namen AUTH trägt und bei dem wir schlicht einen Inhalt erwarten. Natürlich kein Fall für eine echte Anwendung, aber für Darstellungszwecke erst einmal ausreichend.Wir erkennen die Zusammenfassung, die beschreibt, was diese Aktion durchführt. Des Weiteren wurde jeder Parameter definiert und ebenfalls mit einem Kommentar versehen. Man nutzt hier also die Standard-Kommentarblöcke, die auch für IntelliSense verwendet werden.Eine Besonderheit ist jedoch der Response Code. Hier können weitere Rückgabe-Ergebnisse beschrieben werden, die zum Beispiel im Fehlerfall (hier das Fehlen des Authentication-Tokens) übergeben werden.Wer gegebenenfalls neben der Rückgabe eines Datentyps im Fall eines Erfolgs auch unterschiedliche Objekte im Fehlerfall zurückgibt, kann dies über ein weiteres Attribut SwaggerResponse definieren. Hierbei erweitert man die jeweilige Funktion mit zum Beispiel folgenden Attributen:
[SwaggerResponse(HttpStatusCode.OK, Type=typeof(
  ICustomer))] 
[SwaggerResponse(HttpStatusCode.BadRequest, Type = 
  typeof(IEnumerable&lt;MyErrorObject&gt;))] 
[HttpPut] 
public ICustomer Put([FromForm, Required]string name, 
  [FromForm]string firstName, [FromHeader(Name="AUTH")]
  string authenticationToken) 
{ ... } 
Im Erfolgsfall definieren wir hier ganz spezifisch, dass ein ICustomer zurückgemeldet wird. Sollte sich ein BadRequest (HTTP-­Statuscode 400) ereignen, so wird ein Enumerable vom Typ MyErrorObject zurückgeliefert. Ein entsprechender Client kann also darauf reagieren und das zurückgegebene Objekt typisiert deserialisieren und weiterverarbeiten.

Clients auf Knopfdruck

Bis zu diesem Punkt haben wir uns der Generierung und Strukturierung unserer OpenAPI-Spezifikation gewidmet. Client-Entwickler können so mit den typisierten Informationen sicher ihre eigene clientseitige Implementierung durchführen.Webtechnologien wären aber nicht Webtechnologien, wenn es nicht Tools gäbe, die Entwicklern lästige Fleißaufgaben abnehmen würden. Durch OpenAPI und Swagger gibt es mittlerweile unzählige Tools, welche die Spezifikationen nutzen können, um zum Beispiel automatisierte Integrationstests durchzuführen oder clientseitigen Code zu generieren.Am Beispiel von .NET-Entwicklern lohnt es sich, einen Blick auf die Tools des NSwagStudio zu werfen. Dieses Tool kann aus entweder einer .NET Assembly oder der OpenAPI-Spezifikation clientseitigen Code für .NET oder einzelne Web-Frameworks (wie zum Beispiel Angular oder Axios) generieren. Zudem erspart es lästiges und manuelles Integrieren von serverseitigen Web APIs.Auch für andere Sprachen und Bibliotheken gibt es Generatoren, die frei zur Verfügung stehen und teilweise hochgradig individuell konfiguriert werden können.Wer eine Dokumentation zum Beispiel als Webseite oder als tatsächlich druckbares Handbuch benötigt, wird ebenfalls fündig und kann damit gut strukturierte Dokumente erstellen lassen.

Fazit

Moderne Web-API-Entwicklung ist ohne den Einsatz von OpenAPI oder Swagger kaum noch denkbar. Nicht nur kann die lästige Dokumentationstätigkeit stilvoll direkt im Code erledigt werden, sondern man kann sich damit auch die manuelle Schreibarbeit in einem separaten Dokument ersparen. Es gibt damit also einen einzelnen „Punkt der Wahrheit“.Wer Web APIs integrieren muss und bereits die eine oder andere Bekanntschaft mit OpenAPI machen durfte, wird ebenfalls die Vorteile zu schätzen wissen.Jedes API, dessen Dokumentation ausschließlich textuell als PDF existiert und manuell implementiert werden muss, hat angesichts der heutigen Werkzeuge fast schon einen historischen Beigeschmack.

Neueste Beiträge

DWX hakt nach: Wie stellt man Daten besonders lesbar dar?
Dass das Design von Websites maßgeblich für die Lesbarkeit der Inhalte verantwortlich ist, ist klar. Das gleiche gilt aber auch für die Aufbereitung von Daten für Berichte. Worauf besonders zu achten ist, erklären Dr. Ina Humpert und Dr. Julia Norget.
3 Minuten
27. Jun 2025
DWX hakt nach: Wie gestaltet man intuitive User Experiences?
DWX hakt nach: Wie gestaltet man intuitive User Experiences? Intuitive Bedienbarkeit klingt gut – doch wie gelingt sie in der Praxis? UX-Expertin Vicky Pirker verrät auf der Developer Week, worauf es wirklich ankommt. Hier gibt sie vorab einen Einblick in ihre Session.
4 Minuten
27. Jun 2025
„Sieh die KI als Juniorentwickler“
CTO Christian Weyer fühlt sich jung wie schon lange nicht mehr. Woran das liegt und warum er keine Angst um seinen Job hat, erzählt er im dotnetpro-Interview.
15 Minuten
27. Jun 2025
Miscellaneous

Das könnte Dich auch interessieren

UIs für Linux - Bedienoberflächen entwickeln mithilfe von C#, .NET und Avalonia
Es gibt viele UI-Frameworks für .NET, doch nur sehr wenige davon unterstützen Linux. Avalonia schafft als etabliertes Open-Source-Projekt Abhilfe.
16 Minuten
16. Jun 2025
Mythos Motivation - Teamentwicklung
Entwickler bringen Arbeitsfreude und Engagement meist schon von Haus aus mit. Diesen inneren Antrieb zu erhalten sollte für Führungskräfte im Fokus stehen.
13 Minuten
19. Jan 2017
Evolutionäres Prototyping von Business-Apps - Low Code/No Code und KI mit Power Apps
Microsoft baut Power Apps zunehmend mit Features aus, um die Low-Code-/No-Code-Welt mit der KI und der professionellen Programmierung zu verbinden.
19 Minuten
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige