Blog

RESTful APIs dokumentieren – so geht’s!

Jun 19, 2017

© Shutterstock / Freer

Der Begriff API-Economy taucht immer öfter auf und macht so deutlich, wie wichtig Web-APIs sind. Die Verbreitung und damit die Wettbewerbsfähigkeit eines Web-API steht und fällt mit einer guten Dokumentation. Denn sowohl öffentliche als auch interne APIs benötigen einen verständlichen Developer Guide, damit Entwickler sie einsetzen können. Mit den Open-Source-Projekten Swagger2Markup und AsciidoctorJ lässt sich ein Developer Guide erstellen, der sich mit handgeschriebener AsciiDoc-Dokumentation kombinieren lässt und sowohl offline als auch online lesbar ist.
Werde Teil der API-Revolution!
Alle News & Updates zur API Conference 

 

In der letzten Zeit sind viele Spezifikationsformate und Frameworks entstanden, die Spezifikation und Dokumentation eines HTTP-basierten API vereinfachen und vereinheitlichen sollen. Zu den bekanntesten Spezifikationsformaten gehören Swagger (nun OpenAPI-Spezifikation), RAML oder API Blueprint. All diese Projekte haben zum Ziel, ein Spezifikationsformat zu entwickeln, dass zwar maschinenlesbar ist, aber mit dem in erster Linie Menschen arbeiten sollen. Sie nutzen hierfür unterschiedliche Formate wie JSON, YAML oder Markdown. Denn XML-basierte Formate wie die Web Application Description Language (WADL) eignen sich hierfür weniger. Diese Spezifikationsformate für sich alleine sind aber kein Developer Guide wie der GitHub API Developer Guide. Developer Guides sollten weitere Informationen enthalten, wie ein Tutorial mit echten HTTP-Request- und -Response-Beispielen oder Codebeispiele und curl-Kommandos, mit denen sich das API testen lässt.
Swagger ist das momentan am weitesten verbreitete Spezifikationsformat für HTTP-basierte APIs. Um Swagger herum hat sich eine große Toollandschaft gebildet. Ein Beispiel ist die Onlinekollaborationsplattform SwaggerHub, die eine Zusammenarbeit an Swagger-Spezifikationen ermöglichen soll. SwaggerHub unterstützt den gesamten Lebenszyklus eines API und bietet hierfür einen Onlineeditor für das Erstellen einer Swagger-Spezifikation an sowie eine Integration mit GitHub, Versionisierung und Codegenerierung. Ursprünglich war Swagger in der Version 1.2 ein Code-First-Framework, mit dem sich aus Sourcecode eine Swagger-Spezifikation im JSON-Format generieren ließ. Seit Version 2 wird auf einen Contract-First-Ansatz im YAML-Format gesetzt. Die Version 2 wurde von der Open API Initiative als Basis für die OpenAPI-Spezifikation übernommen. SwaggerHub bietet einen Onlineeditor an, mit dem sich ein API erstellen und validieren lässt (Abb. 1).

 

YAML ist eine Auszeichnungssprache zur Datenserialisierung und eine Übermenge von JSON. Das Akronym YAML steht für „YAML Ain’t Markup Language“. YAML ist leichter von Menschen zu lesen und zu schreiben als beispielsweise JSON oder XML.

 

Abb. 1: Mit dem SwaggerHub-Onlineeditor lassen sich APIs erstellen und validieren

 

In Listing 1 ist ein Ausschnitt der Swagger-Petstore-API-Demospezifikation zu sehen. Eine Swagger-Spezifikation muss immer Metainformationen wie einen Titel und eine Version enthalten. Der Hostname und ein Basispfad sind nicht zwingend notwendig. Anschließend können API-Endpunkte, globale Parameter, globale Antwortnachrichten und globale Datentypen spezifiziert werden. Der API-Endpunkt /pets/{petId} beispielsweise ermöglicht es, die Ressource Pet über eine ID zu finden. Innerhalb des API-Endpunkts werden die Inputparameter des Endpunkts und die möglichen Antwortnachrichten spezifiziert. Die Antwortnachricht mit dem Statuscode 200 referenziert die globale Definition für das Pet-Datenmodell, das in der Antwortnachricht zurückgeliefert wird. Mit Swagger lassen sich viele HTTP-basierte APIs abbilden. Lediglich HATEOAS als finales Level eines Restful API kann Swagger derzeit noch nicht abbilden.

 

    swagger: "2.0"
info:
  description: This is a sample server Petstore server.
  version: "1.0.0"
  title: Swagger Petstore
host: petstore.swagger.wordnik.com
basePath: /v2
schemes:
  - https
paths:
  /pets/{petId}:
    get:
      tags:
        - pet
      summary: Find pet by ID
      description: Returns a pet
      produces:
        - application/json
      parameters:
        - in: path
          name: petId
          description: ID of pet that needs to be fetched
          required: true
          type: integer
          format: int64
      responses:
        "200":
          description: successful operation
          schema:
            $ref: "#/definitions/Pet"
        "400":
          description: Invalid ID supplied
        "404":
          description: Pet not found
definitions:
  Pet:
    required:
      - name
      - photoUrls
    properties:
      id:
        type: integer
        format: int64
      category:
        $ref: "#/definitions/Category"
      name:
        type: string
        example: doggie
      status:
        type: string
        description: pet status in the store

 

Abb. 2: Die Swagger-HTML-Dokumentation ist interaktiv


Abbildung 2
zeigt die von SwaggerHub erstellte interaktive HTML-Dokumentation. Diese interaktive HTML-Dokumentation hat einige Mankos. Zum einen liegt der Fokus der Dokumentation eindeutig auf den API-Endpunkten, z. B. GET /pets/{petId}, und nicht auf einer kurzen Beschreibung der Funktionalität, die von diesem Endpunkt angeboten wird, z. B. „Find Pet by ID“. Ein Entwickler, der das API nicht kennt, würde in erster Linie nicht nach einem konkreten API-Endpunkt suchen, sondern nach der von ihm benötigten Funktionalität. Des Weiteren lässt sich die HTML-Dokumentation nicht offline anschauen oder als PDF exportieren. Ein PDF-Format ist aber häufig notwendig, wenn die API-Dokumentation in einer Ausschreibung für ein Softwareprojekt mit ausgehändigt werden muss. Ein weiteres Manko ist, dass sich diese Dokumentation nicht um weitere Informationen erweitern lässt, z. B. um Nutzungsbeispiele in verschiedenen Programmiersprachen. Es stellen sich also zwei Fragen:

  • Wie kann eine Swagger-Spezifikation um handgeschriebene Dokumentation erweitert werden?
  • Wie kann die Dokumentation sowohl im HTML- als auch im PDF-Format erstellt werden?

Hierbei können uns die Projekte AsciidoctorJ und Swagger2Markup behilflich sein.

 

Mit AsciiDoc und AsciidoctorJ Dokumente erstellen

AsciiDoc ist eine Auszeichnungssprache vergleichbar mit Markdown, allerdings von der Funktionalität deutlich umfangreicher. AsciiDoc-Dateien lassen sich mithilfe von AsciidoctorJ in mehrere Formate wie HTML, PDF, EPUB oder DocBook konvertieren. AsciiDoc, aber auch Markdown, eignen sich hervorragend dafür, eine handgeschriebene technische Dokumentation zu erstellen. Ein einfaches AsciiDoc-Dokument sieht wie in Listing 2 aus.

 

= Introduction to AsciiDocDoc
Writer <[email protected]>
A preface about http://asciidoc.org[AsciiDoc].
 
== First Section
* list item 1
* list item 2
 
_italic phrase_
*bold phrase*
`monospace phrase`
 
[source,ruby]
puts "Hello, World!"
 
image::example.jpg[]
include::second_section.adoc[]

 

Mit AsciiDoc lässt sich ein Dokument in Kapitel unterteilen. Ein großer Vorteil von AsciiDoc gegenüber Markdown ist, dass man mithilfe der Include-Direktive große Dokumente in kleine Dateien aufteilen kann. Außerdem lassen sich Texte formatieren und Listen, Tabellen und Sourcecode darstellen. Man kann auch UML-Diagramme erstellen und Bilder, Videos oder Audio einbauen. Da AsciiDoc nur Plain Text ist, kann es mit Git versioniert werden und ermöglicht somit das Arbeiten mit mehreren Leuten an einer Dokumentation. Mit Word-Dateien ist dies nicht möglich. Mit AsciidocFX gibt es auch einen tollen JavaFX-basierten Editor, um AsciiDoc-Dokumente mit Live Preview zu schreiben. Bekannte Open-Source-Projekte wie das Spring Framework oder Spring Boot nutzen AsciiDoc für das Erstellen der Dokumentation.

 

Mit Swagger2Markup konvertieren

Mit Swagger2Markup gibt es ein Open-Source-Projekt, das es ermöglicht, eine Swagger-Spezifikation in AsciiDoc, Markdown oder Atlassian Confluence Wiki Markup zu konvertieren. Die Swagger-Spezifikation kann im YAML- und im JSON-Format vorliegen und sowohl lokal als auch remote über HTTP geladen werden. Die Verwendung von Swagger2Markup ist simpel. Listing 3 zeigt, wie man mit dem Swagger2MarkupConverter eine Swagger-Spezifikation in AsciiDoc konvertieren kann. AsciiDoc ist als Standardausgabeformat vorkonfiguriert. Es müssen nur die Quelle und der Zielordner angegeben werden. In diesem Beispiel wird die Swagger-Petstore-API-Demospezifikation über HTTP geladen.

 

URL remoteSwaggerFile = new URL("http://petstore.swagger.io/v2/swagger.json");
Path outputDirectory = Paths.get("build/asciidoc");
Swagger2MarkupConverter.from(remoteSwaggerFile)   
  .build()
  .toFolder(outputDirectory);

 

Standardmäßig werden aus einer Swagger-Spezifikation vier AsciiDoc-Dateien generiert: overview.adoc, security.adoc, paths.adoc und definitions.adoc. Diese generierten Dateien lassen sich mit handgeschriebenen AsciiDoc-Dateien (z. B. hand_written_1.adoc und hand_written_2.adoc) beliebig kombinieren. Swagger2Markup kann aber auch einzelne Dateien für jeden API-Endpunkt und Datentyp generieren. Die handgeschriebene Dokumentation kann Informationen enthalten, die mit Swagger alleine nicht möglich sind, z. B. ein Tutorial zur Nutzung des API mit Request- und Response-Beispielen. Hierzu erstellt man eine AsciiDoc-Datei index.adoc, die mithilfe der Include-Direktive alle Dateien mit einschließt (Listing 4). Der Platzhalter {generated} steht für den Ordner, in den die Dateien generiert wurden.

 

include::{generated}/overview.adoc[]
include::manual_content1.adoc[]
include::manual_content2.adoc[]
include::{generated}/security.adoc[]
include::{generated}/paths.adoc[]
include::{generated}/definitions.adoc[]

 

Mithilfe des Open-Source-Projekts AsciidoctorJ lässt sich die index.adoc-Datei in HTML, PDF oder andere Formate konvertieren. Listing 5 zeigt beispielsweise eine Konvertierung in HTML mit Kapitelnummerierung und einer Inhaltsangabe auf der linken Navigationsseite.

 

String asciiDocAsHtml = 
Asciidoctor.Factory.create().convertFile(Paths.get("build/asciidoc/index.adoc").toFile(), OptionsBuilder.options().backend("html5").headerFooter(true).safe(SafeMode.UNSAFE).attributes(AttributesBuilder.attributes().tableOfContents(true).tableOfContents(Placement.LEFT).sectionNumbers(true)));

 

Für Swagger2Markup und AsciidoctorJ gibt es aber auch Gradle- oder Maven-Plug-ins, um die Konvertierung in einer Build-Pipeline durchführen zu können. Auf GitHub gibt es zwei Templateprojekte, die den Start mit Gradle oder Maven vereinfachen. Die generierte HTML- oder PDF-Dokumentation sieht dann wie in Abbildung 3 aus. Der Fokus der generierten Inhaltsangabe (ToC) liegt auf der Funktionalität, die von dem API angeboten wird, und nicht auf den konkreten API-Endpunkten.

Abb. 3: Das Resultat ist eine manuell angereicherte, gut strukturierte Dokumentation – hier in HTML

Swagger2Markup hat viele Konfigurationsparameter und lässt sich über verschiedene Wege konfigurieren, u. a. System-Properties, Properties-Datei, Map oder Fluent-Builder-API. Listing 6 zeigt die Verwendung des Fluent-Builder-API, um das Ausgabeformat und die Ausgabesprache zu ändern. Mithilfe des Swagger2MarkupConfigBuilder kann eine Swagger2MarkupConfig gebaut werden, die dann der Swagger2MarkupConverter verwendet. Derzeit werden als Sprachen Englisch, Deutsch, Französisch, Russisch und Türkisch unterstützt.

 

Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
  .withMarkupLanguage(MarkupLanguage.MARKDOWN)
  .withOutputLanguage(Language.DE)
  .withPathsGroupedBy(GroupBy.TAGS)
  .build();
  
Swagger2MarkupConverter converter = 
Swagger2MarkupConverter.from(localSwaggerFile)
  .withConfig(config)
  .build();

 

Swagger2Markup stellt auch ein Service Provider Interface (SPI) und Extension Points bereit, mit denen man eigene Extensions entwickeln und somit den Funktionsumfang von Swagger2Markup erweitern kann. Mithilfe von Gradle oder auch Maven lässt sich eine lokale Swagger-Spezifikation, die standardmäßig in dem Ordner src/docs/swagger liegen muss, automatisiert konvertieren. Hierfür müssen das Swagger2Markup- und das AsciidoctorJ-Gradle-Plug-in-geladen und die Tasks convertSwagger2markupund asciidoctor konfiguriert werden (Listing 7). Standardmäßig sucht das AsciidoctorJ-Plug-in in dem Ordner src/docs/asciidoc nach den AsciiDoc-Dateien. In diesem Beispiel wird nur die Datei index.adockonvertiert und somit auch alle Dateien, die darin enthalten sind. Mit dem Kommando gradlew asciidoctorlässt sich nun eine HTML- und PDF-Dokumentation generieren. Die HTML- und PDF-Dokumentation wird in den Ordner build/asciidoc/html5 beziehungsweise build/asciidoc/pdf erstellt.

 

buildscript
 {  dependencies {
    classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.3'
    classpath 'io.github.swagger2markup:swagger2markup-gradle-plugin:1.0.1'
  }
}
 
apply plugin: 'org.asciidoctor.convert'
apply plugin: 'io.github.swagger2markup'
 
ext {
  asciiDocOutputDir = file("${buildDir}/asciidoc")
}
convertSwagger2markup {
  swaggerInput file("src/docs/swagger/swagger_petstore.yaml").getAbsolutePath()
  outputDir asciiDocOutputDir
  config = ['swagger2markup.markupLanguage' : 'ASCIIDOC',
            'swagger2markup.pathsGroupedBy' : 'TAGS']
}
 
asciidoctor {
  dependsOn convertSwagger2markup
  sources {
    include 'index.adoc'
  }
  backends = ['html5', 'pdf']
  attributes = [
    generated: asciiDocOutputDir
  ]
}

 

Alle News & Updates zur API Conference:

Behind the Tracks

API Management

Ein detaillierter Blick auf die Entwicklung von APIs

API Development

Architektur von APIs und API-Systemen

API Design

Von Policys und Identitys bis Monitoring

API Platforms & Business

API Plattformen in Verbindung mit SaaS