Wybierz region
pl
  • PL
  • EN
Wydrukuj

Generowanie serwera REST z użyciem Open Api

W tym artykule opiszę połączenie gralde + spring boot + open api (aka swagger) oraz jak przy pomocy tego połączenia wygenerować serwer REST Api. Na końcu artykułu znajdują się linki do pełnego kodu aplikacji. Poniżej postaram się przybliżyć i wyjaśnić najważniejsze jego części.

Jak już wspomniałem, aby wygenerować serwer REST potrzebować będziemy trzech rzeczy. Pliku zawierającego definicję API z rozszerzeniem .yaml. Umieszczone w nim będą ścieżki i parametry naszych usług. Potrzebować będziemy również narzędzia automatyzującego budowę, którego użyjemy do ściągnięcia i użycia bibliotek odpowiedzialnych za zbudowanie rozwiązania. Potrzebowali w końcu będziemy samych bibliotek, przy pomocy których wygenerujemy kod serwera.


Konfigurację rozpoczynamy od wprowadzenia niezbędnych zmian do narzędzia automatyzującego budowę. Plik Build.gradle jest plikiem konfiguracyjnym gradle i to w nim dokonywać będziemy pierwszych zmian. Na początku definiujemy importy klas, z których będziemy korzystać w dalszej części. Klasy te to CodegenConfigurator i DefaultGenerator — są on odpowiedzialne za wygenerowanie kodu serwera ze wskazanego przez nas pliku yaml. W tym utworzonym przez nas pliku, zawieramy definicję jak powinien wyglądać interfejs naszego serwera, jego punkty wejściowe, ich nazwy i ścieżki, a także wymagane parametry.

 

Następnie definiujemy zadanie task generate, będzie ono odpowiedzialne za generowanie docelowego API. W jego wnętrzu znajdziemy wytyczne generowania, m.in. ścieżkę do pliku yaml, z którego generowany będzie kod serwera — config.setInputSpec. Znajdziemy również ścieżkę do miejsca docelowego przechowywania wygenerowanego kodu -config.OutputDir. Zamiennie z parametryzacją zamieszczoną w kodzie poniżej rootProject.swaggerFile.toString(), gdzie parametr swaggerFile zdefiniowany jest wcześniej, możemy również użyć bezpośredniego wpisania ścieżki np. d:\przykladowaAplikacja\example.yaml. W dodatkowych ustawieniach AdditionalProperties widzimy, że nasz serwer ma używać bibliotek javy8 do obsługi dat oraz że mają zostać wygenerowane jedynie interfejsy serwera REST, które my przykryjemy własnym kodem.

Następną istotną częścią konfiguracji jest ustawienie zależności, czyli ściągnięcia do projektu pakietów dzięki, którym będziemy mogli uruchomić naszą aplikację.

Poniżej krótki opis artefaktów, których będziemy używali:


  • spring-boot-starter-parent - ustawia Jave 1.8 jako domyślną kompilację oraz domyślne kodowanie UTF-8. Pozwala również na używanie profilów dla aplikacji przez definiowanie plików application.properties takich jak application-dev.properties dla środowiska dev, czy application-test.properties dla środowiska testowego.

  • spring-boot-maven-plugin – służy do budowy wykonywalnego pliku jar/war, jest także potrzeby do importu i użycia klas codegen.

  • spring-boot-starter-web - odpowiada za dostarczenie bibliotek do uruchomienia projektu springowego, takich jak na przykład biblioteki serwera tomcat, do łatwego i szybkiego uruchomienia aplikacji.
    io.springfox:springfox-swagger2 – jest to implementacja swaggera do generowania API, którego będziemy używali w naszym projekcie.

  • springfox-swagger-ui – jest nakładką graficzną i służy do graficznego reprezentowania wygenerowanego API. Prezentacja wygenerowanego API, będzie zwieńczeniem wykonania naszego projektu.


Jako następną definiujemy klasę odpowiedzialną za konfigurację uruchomienia swaggera. W tym przypadku została ona umieszczona w pakiecie config. @EnableSwagger2 służy jako włącznik swaggera i pozwala na jego konfigurację. W poniższym przykładzie widzimy zdefiniowanego beana Docket, przy pomocy ustawień którego, możemy zdefiniować takie wartości jak nazwę aplikacji, ścieżki oraz pakiety, które zostaną użyte do generowania serwera. W poniższym przykładzie głównymi elementami są apis i paths, które mamy zdefiniowane jako any, czyli wszystkie dostępne.

Możemy jednak zdefiniować je również w sposób jak poniżej:

Daje nam to większą kontrolę nad generowanym kodem, przez możliwość decydowania co wchodzi w skład serwera. Możemy zdefiniować pakiet, z którego generowane będzie API, a także ścieżki dostępu serwera, które mają zostać użyte. Zarówno paths jak i apis dają również możliwość użycia regexów, aby można było użyć np. jedynie ścieżek, które mieszczą się w ich definicji.

Przejdźmy teraz do opisu samego pliku na podstawie którego generowany będzie serwer. Jak już wcześniej wspomniałem jest to plik yaml, w którym zawarte są definicje serwera. W nagłówku pliku znajdziemy definicję swaggera, w tym przypadku jest to wersja 2.0, oraz opis aplikacji i jej wersja.

Następną istotna częścią jest ścieżka pod jaką dostępny będzie punkt wejściowy naszej aplikacji. Pod taką ścieżką, po uruchomieniu serwera, wywołać będziemy mogli naszą aplikację.

Poniższa sekcja odpowiada za zdefiniowanie odpowiedzi z aplikacji wywołanej pod ścieżką wymienioną powyżej. W tym przypadku widzimy, że wołając aplikację na ścieżce /car/find otrzymamy w odpowiedzi kolekcję type: „array” zawierającą obiekty typu Car. Następna linijka items: $ref: „#definitions/Car”, odsyła nas do sekcji definitions, gdzie znajduje się definicja samego obiektu Car.

Następnie mamy definicję parametru wejściowego dla funkcji działającej na wymienionej wyżej ścieżce. Co oznacza, że gdy będziemy uruchamiali serwer z podaną ścieżką /car/find, jako parametr będzie wymagany obiekt CarUser. Mamy także ustalenie jego nazwy name: CarUser oraz miejsca, w którym opisana jest jego definicja $ref: „#/definitions/CarUser”, na podstawie której zostanie wygenerowany.

W miejscu opisu obiektów w sekcji definitions, widzimy opis dwóch, wspomnianych już wcześniej obiektów, Car oraz CarUser. Będą one generowane przez swaggera. Obiekt CarUser, został dodatkowo zadeklarowany jako parametr wejściowy dla wyżej wymienionej ścieżki /car/find.

Gdy mamy już to wszystko gotowe możemy przystąpić do generowania kodu naszego serwera.

W terminalu wykonujemy proste polecenie gradle generate, które zostało przez nas zdefinowane w pliku build.gradle. Za jego pomocą wygenerowany zostanie kod naszego serwera.

Powyżej wynik wykonania, czyli zdeklarowane przez Nas klasy i interfejs wejściowy.

To co nam pozostało to implementacja interfejsu i napisanie własnoręcznie klas obsługujących żądania przychodzące do serwera. Poniżej prosty przykład jak może to wyglądać. Widźmy tu funkcję będącą implementacją funkcji interfejsu CarApi. Przyjmuje ona parametr CarUser i zwraca listę typu Car. W naszym przykładzie nie ma żadnej skomplikowanej logiki, jedynie dla przykładu tworzymy nowy samochód o nazwie Corvette o jakimś tajemniczym identyfikatorze 1. Wkładamy tak przygotowany obiekt do listy i zwracamy na wyjściu dodatkowo opakowane w Klasę ResponseEntity.

Finalnie uruchamiamy to wszystko za pomocą polecenia gradle bootrun wpisanego do terminala. Ponieważ użyliśmy graficznej prezentacji wygenerowanego przez nas serwera, po uruchomieniu aplikacji, nasz serwer zostanie uruchomiony pod adresem http://localhost:8080/swagger-ui.html i naszym oczom ukażę się poniższy widok.

Linki do kodu na github: 

https://github.com/bohun82/OpenApiExample


Piotr Wójcik

Programista Java, od 12 lat związany z branżą IT i programowaniem. Programowanie jest moją pracą, ale także jednym z hobby.


Wydrukuj