Swagger. Jak stworzyć dokumentację API

Dokumentacja jest nieodzownym elementem każdego API; bez niej niezwykle trudno dowiedzieć się, jakie końcówki są dostępne, do czego służą i jakich parametrów możemy użyć. Najciekawszym narzędziem do tworzenia interaktywnej dokumentacji API, z jakim się spotkałem, jest Swagger. O ile wykorzystanie go w projekcie w języku Java z frameworkiem Spring jest proste, o tyle w innych językach jest nieco trudniej. Jak zatem się do tego zabrać?

Zacznijmy od tego, czym jest interaktywna dokumentacja API, w odróżnieniu od klasycznego opisu w płaskim pliku tekstowym lub readme. Taka interaktywna dokumentacja pozwala nie tylko przejrzeć dostępne końcówki, ich parametry, czy schematy zwracanych wartości, ale przede wszystkim umożliwia wypróbowanie ich. Jest to przydatne nie tylko do znalezienia interesującej nas końcówki, ale też do wywoływania ich na życzenie, co nieraz okazuje się przydatne w trakcie developmentu.

Swaggera używam w przypadku aplikacji pisanych w języku Java. Istnieje paczka, która za pomocą kilku adnotacji umożliwia automatyczne wygenerowanie dokumentacji. Korzysta ona przy tym z faktu, że Java jest językiem silnie typowanym, dzięki czemu nie ma potrzeby ręcznego definiowania wszystkich parametrów, czy też schematów zwracanych danych. Swagger robi to za nas.

W Node.js albo PHP (a zapewne też w wielu innych językach interpretowanych) nie ma takiego udogodnienia. Brak silnego typowania oznacza, że żadna paczka, moduł, czy biblioteka nie domyśli się, jakie są możliwe parametry wejściowe i co dokładnie zostanie zwrócone przez daną końcówkę. Nie ma zatem żadnego narzędzia podobnego do tego znanego z Javy. Trzeba sobie radzić inaczej.

Na początku próbowałem swoich sił z inną paczką o, na pierwszy rzut oka, podobnych możliwościach: apidoc. O ile generowana dokumentacja jest, oględnie rzecz biorąc, podobna, o tyle dość szybko okazało się, że problemem jest definiowanie parametrów pochodzących z różnych źródeł (nagłówek, element adresu URL, query string, treść żądania) oraz ich oczekiwanych schematów. O ile pewne utrudnienia dawało się przeskoczyć, o tyle w pewnym momencie stwierdziłem, że są sytuacje, kiedy dokumentacja danej końcówki jest po prostu niepełna albo wręcz nie działa prawidłowo.

Swagger zaś, choć wiedziałem, że buduje znacznie lepsze funkcjonalnie dokumentacje, nie za bardzo oferował łatwego sposobu na użycie go. Sposób oczywiście zawsze się znajdzie i w najgorszym razie można po prostu ręcznie edytować plik z dokumentacją w formacie JSON. Jest to jednak trudne i podatne na błędy. Sposób, choć nie idealny, mimo wszystko się znalazł.

Zacznijmy od instalacji paczki Swaggera. Wymaga ona Node.js (nie oznacza to jednak, że jest używalna jedynie w projektach Node.js).

npm install -g swagger

Od tego momentu mamy dostępne w terminalu polecenie swagger. Polecenie to jednak zakłada, że będziemy budowali aplikacje Node.js z użyciem jednego ze wspieranych frameworków, a do tego z odgórnie narzuconą strukturą katalogów. Za jego pomocą możemy stworzyć projekty korzystające z frameworka Express, Connect i kilku innych opcji. Tworzy to zawsze z góry ustaloną strukturę katalogów i do tejże struktury się odnosi. Nie znam sposobu jej modyfikacji. Dlatego też tylko kilka opcji będzie dla nas użytecznych.

Po pierwsze, wyświetlmy sobie specyfikację plików z dokumentacją Swaggera:

swagger docs

To polecenie otworzy specyfikację, według której musimy stworzyć naszą dokumentację. Korzystać będziemy z formatu YAML. Wiem, że informacje tu zawarte są dość ciężką lekturą, ale nieraz okazują się bardzo przydatne, zwłaszcza na początku, kiedy nie wiemy, jakie klucze są dostępne, które z nich są obowiązkowe i jakie wartości mamy dostępne. Polecam trzymanie tej strony w otwartej zakładce podczas edytowania dokumentacji.

Teraz zaś sama dokumentacja. Stwórzmy sobie plik api/swagger/swagger.yaml (ścieżka relatywna do głównego katalogu projektu). Niestety nie udało mi się znaleźć sposobu na umieszczenie tego pliku w dowolnej lokalizacji — jeśli kiedyś na taki sposób trafię, to opublikuję stosowną aktualizację. Do tego czasu jednak trzeba poświęcić nieco elastyczności i przeżyć z takim odgórnie narzuconym umiejscowieniem pliku.

W terminalu odpalmy komendę:

swagger project edit

W przeglądarce powinien uruchomić się edytor YAML z aktualizowanym na bieżąco podglądem dokumentacji. Wszelkie błędy również są na bieżąco wyświetlane, możemy zatem na bieżąco poprawiać je. Co prawda wyjaśnienia, co dokładnie zrobiliśmy źle nie zawsze są oczywiste, ale zawsze można bezpiecznie założyć, że jeśli pojawił się nowy błąd, to dotyczy on dopiero co napisanego kawałka kodu, co mocno zawęża pole poszukiwań. Edytowany plik jest automatycznie zapisywany.

Drugą częścią zadania będzie pobranie UI Swaggera. Możemy zainstalować sobie gotową paczkę, z której bez problemu pobierzemy potrzebne nam pliki:

npm install swagger-ui

lub

bower install swagger-ui

W obu przypadkach nie użyłem flagi --save ani --save-dev z rozmysłem: paczki są nam potrzebne tylko w celu skopiowania plików, które będziemy serwować w naszej aplikacji. W pobranej paczce znajduje się katalog dist/. Jego zawartość kopiujemy do katalogu z plikami statycznymi. Sprawdźmy, czy wchodząc na główny adres naszej aplikacji, widzimy dokumentację Swaggera z przykładowym API. Jeśli nie, to coś poszło nie tak i trzeba temu zaradzić. Jeśli tak, to możemy przejść do kolejnego etapu, jakim jest stworzenie pliku dokumentacji JSON.

Ja wykorzystuję do tego zadanie Gulp.js:

var gulp = require("gulp");
var yaml = require("js-yaml");
var path = require("path");
var fs = require("fs");

gulp.task("swagger", function() {
    var file = path.join(__dirname, "../api/swagger/swagger.yaml");
    var doc = yaml.safeLoad(fs.readFileSync(file));
    fs.writeFileSync(
        path.join(__dirname, "../public/swagger.json"),
        JSON.stringify(doc, null, "  ")
    );
});

W powyższym kodzie widać, że zadanie znajduje się w innym katalogu niż plik z dokumentacją, ale zakładam, że dla każdego ustalenie prawidłowej ścieżki będzie bezproblemowe. Zadanie korzysta z paczki js-yaml, która służy do odczytania zawartości pliku wejściowego. Plik zaś jest odczytywany i zapisywany już w formacie JSON bezpośrednio w katalogu z plikami statycznymi.

Warto napisać sobie jeszcze zadanie, które będzie śledziło zmiany w pliku YAML i na bieżąco przetwarzało go na format JSON:

var gulp = require("gulp");

gulp.task("watch", function() {
    gulp.watch("api/swagger/swagger.yaml", ["swagger"]);
});

Uruchamiając powyższe zadanie, możemy swobodnie edytować plik YAML w edytorze Swaggera, a wszelkie zmiany zostaną automatycznie wychwycone i będziemy mieli zawsze aktualny plik JSON.

Ostatnim krokiem jest modyfikacja pliku index.html w naszym UI. Plik domyślnie dostarczony z paczką Swagger UI korzysta z przykładowej dokumentacji API. Zaglądając do wnętrza pliku, znajdziemy tam taki fragment kodu JavaScript:

var url = window.location.search.match(/url=([^&]+)/);
if (url && url.length > 1) {
    url = decodeURIComponent(url[1]);
} else {
    url = "http://petstore.swagger.io/v2/swagger.json";
}

Wystarczy zamienić wyrażenie w klamrze else, podając w nim adres naszego pliku swagger.json:

url = "/swagger.json";

I to tyle. Możemy teraz uruchomić serwer i sprawdzić, jak Swagger UI sobie radzi z naszym API.


Napisz komentarz


Szukaj wpisów


Chmura tagów