6. September 2023 von Claudio Altamura
API Spezifikationen mit OpenAPI Style Validator prüfen
APIs und ihre Spezifikationen werden verständlicher, wenn sie Beschreibungen, Beispiele und Namenskonventionen verwenden. Genau hier setzt der OpenAPI Style Validator an. Das Tool kann als Bibliothek im Java-Code oder mit Hilfe eines Maven-Plugins in einer CI/CD-Pipeline eingesetzt werden.
Das Problem mit API-Spezifikationen
Häufig sind Spezifikationen nicht eindeutig und präzise. So fehlen neben aussagekräftigen Beschreibungen auch Beispiele, die den Einsatz verdeutlichen. Hier kann der OpenAPI Style Validator helfen, genau solche Schwächen in OpenAPI-Spezifikationen zu finden. Definierte Regeln beschreiben, wie Elemente einer API-Spezifikation auszusehen haben. Dadurch kann das Werkzeug Spezifikationen automatisiert prüfen. Beim Einsatz in einer Build-Pipeline können Regelverstöße sogar zu einem Build-Break führen.
Ausführliche Beschreibungen
Um die Vorteile des OpenAPI Validators näher zu erläutern, nehmen wir das beliebte Petstore-Beispiel.
Eine OpenAPI-Beschreibung beginnt bekanntlich mit dem Info-Objekt und den zugehörigen Contact- und License-Objekten (siehe Listing 1). An dieser Stelle finden sich oft schon die ersten Regelverstöße. Beim Info-Objekt werden Titel und Beschreibung vernachlässigt, Kontakt- oder Lizenzinformationen fehlen meist komplett.
{
"info": {
"version": "1.0.0",
"title": "Swagger Petstore",
"description": "A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"name": "Swagger API Team",
"email": "apiteam@swagger.io",
"url": "http://swagger.io"
},
"license": {
"name": "Apache 2.0",
"url": "https://www.apache.org/licenses/LICENSE-2.0.html"
}
}
…
}
Listing 1: Info-Objekt
Die meisten Regelverletzungen treten jedoch auf der Ebene der Path- oder Operation-Objekte auf. Diese Objekte sind dem Paths-Objekt untergeordnet. Das Paths-Objekt enthält alle Pfade zu den vorhandenen Endpunkten (Path Items). Ein einzelner Path ( zum Beispiel /pets GET) enthält dann die Operationen, also die erlaubten Methoden.
{
…
"/pets/{id}": {
"get": {
"description": "Returns a user ba
sed on a single ID, if the user does not have access to the pet",
"operationId": "find pet by id", "parameters": [
{
"name": "id",
"in": "path",
"description": "ID of pet to fetch",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
}
}
],
…
}
}
…
}
Listing 2: Das Operation-Objekt GET
Das Tool kann hier erkennen, ob bestimmte Properties vorhanden und gefüllt sind. In Listing 2 fehlt beispielsweise die Property “summary”. Dafür ist aber “description” vorhanden.
Der nächste interessante Abschnitt in Reviews sind in der Regel die Datentypen. Datentypen sind in der OpenAPI-Spezifikation als Schema-Objekte definiert, die dann in Requests oder Responses referenziert werden ( zum Beispiel "$ref": "#/components/schemas/NewPet"). Bei Schema-Objekten prüft der Validator, ob alle Schema-Properties vorhanden und nicht leer sind.
Wenn wir uns das Petstore-Beispiel NewPet in Listing 3 ansehen, fällt auf, dass keine Descriptions und Examples vorhanden sind. Descriptions und Examples sind meiner Meinung nach ein zentrales Element, um API-Dokumentationen verständlicher zu machen und APIs zu erlernen.
{
…
"NewPet": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string"
},
"tag": {
"type": "string"
}
}
},
…
}
Listing 3: Das Schema-Objekt NewPet
Namenskonventionen
Nun zu den Konventionen. Namenskonventionen sind meiner Meinung nach ebenfalls ein wichtiger Bestandteil von API-Richtlinien. Schließlich sollen solche Richtlinien die Zusammenarbeit, Stabilität und Erweiterbarkeit von APIs sicherstellen.
Der OpenAPI Style Validator unterstützt eine Reihe verschiedener Namenskonventionen, die wir für Pfade, Parameter, Header oder Properties verwenden können. Ich spreche hier zum Beispiel von underscore_Case, camelCase oder Kebab-Case. Über Optionen wie
- pathNamingConvention,
- parameterNamingConvention,
- pathParamNamingConvention,
- queryParamNamingConvention,
kann festgelegt werden, wie etwa. ein Pfad aussehen soll. Unter [1] sind alle Möglichkeiten aufgeführt.
Aufruf
Für Maven kann ein Plugin konfiguriert werden:
…
<plugin>
<groupId>org.openapitools.openapistylevalidator</groupId>
<artifactId>openapi-style-validator-maven-plugin</artifactId>
<version>1.9</version>
<configuration>
<inputFile>petstore-expanded.json</inputFile>
<validateOperationTag>false</validateOperationTag>
</configuration>
<dependencies>
<dependency>
<groupId>org.openapitools.empoa</groupId>
<artifactId>empoa-swagger-core</artifactId>
<version>2.1.0</version>
<exclusions>
<exclusion>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</plugin>
…
Listing 4: Konfiguration des Maven Plug-ins in der pom.xml
Jede Option kann als Parameter in einem XML-Tag hinzugefügt werden. Stellen wir uns folgenden hypothetischen Fall vor. Wir haben eine kleine OpenAPI-Beschreibung und möchten hier auf den Operation-Tag verzichten. Dann können wir, wie in Listing 4 gezeigt, die Validierung mit der Option "validateOperationTag" und "false" als Inhalt ausschalten. Schließlich kann der Validator mit dem folgenden Befehl ausgeführt werden:
mvn openapi-style-validator:validate
Mit dieser Konfiguration erhalten wir für das Beispiel Petstore ein sehr anschauliches Testergebnis, das aufgrund von Regelverletzungen zu einem Build Break führt:
[INFO] --- openapi-style-validator:1.9:validate (default-cli) @ openapi-style-validator-example ---
[INFO] Validating spec: petstore-expanded.json[ERROR] OpenAPI Specification does not meet the requirements. Issues:*
[ERROR] *ERROR* in Operation GET /pets 'summary' -> This field should be present and not empty
[ERROR] *ERROR* in Operation POST /pets 'summary' -> This field should be present and not empty
[ERROR] *ERROR* in Operation GET /pets/{id} 'summary' -> This field should be present and not empty
[ERROR] *ERROR* in Operation DELETE /pets/{id} 'summary' -> This field should be present and not empty
[ERROR] *ERROR* in Model 'NewPet', property 'name', field 'example' -> This field should be present and not empty
[ERROR] *ERROR* in Model 'NewPet', property 'name', field 'description' -> This field should be present and not empty
[ERROR] *ERROR* in Model 'NewPet', property 'tag', field 'example' -> This field should be present and not empty
[ERROR] *ERROR* in Model 'NewPet', property 'tag', field 'description' -> This field should be present and not empty
[ERROR] *ERROR* in Model 'Error', property 'code', field 'example' -> This field should be present and not empty
[ERROR] *ERROR* in Model 'Error', property 'code', field 'description' -> This field should be present and not empty
[ERROR] *ERROR* in Model 'Error', property 'message', field 'example' -> This field should be present and not empty
[ERROR] *ERROR* in Model 'Error', property 'message', field 'description' -> This field should be present and not empty
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.067 s
Fazit
Der OpenAPI Style Validator findet unvollständige Beschreibungen und inkonsistente Verwendung von Namenskonventionen. Das Werkzeug ist eine Hilfe bei der Umsetzung von API-Richtlinien. Durch definierte Regeln kann API-Spezifikationen ein einheitliches “Look and Feel” gegeben werden.