Spring Boot + Swagger UI

Tworząc aplikację w Spring Boocie, która udostępnia API przez web serwisy, czasem potrzebujemy wejść z nią w jakąś interakcję. Czy to w celach testowych, czy po prostu uruchomić nasz serwis, aby wykonał jakąś czynność. Możemy w tym celu użyć różnych narzędzi jak Postman, curl czy chociażby przeglądarki jeśli chcemy wykonać zapytanie GET. Jednak te narzędzia nie są świadome, jakich danych oczekuje nasz serwis oraz jakie endpointy są w nim dostępne. Możemy oczywiście w tym celu stworzyć sobie jakiś interfejs użytkownika, przez który będziemy mogli podejmować interakcję z aplikacją, jednak wymaga to jakiegoś nakładu pracy. I tutaj z pomocą może nam przyjść Swagger UI. Po prostu dołączamy go do projektu, a on sam przeskanuje aplikację i wygeneruje nam stronę www, przez którą będziemy mogli podejmować interakcję z naszą aplikacją. Dodatkowo możemy udokumentować API, dodając odpowiednie adnotacje w kodzie.

Kod źródłowy do wpisu znajduje się jak zawsze w repozytorium GitHuba pod adresem: https://github.com/mloza/spring-boot-swagger-ui.

Tworzymy apikację

Na początek stwórzmy sobie aplikację w Spring Boocie. Tworzymy nowy projekt Mavenowy i dodajemy zależności. Nasz pom powinien wyglądać jak poniżej.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>pl.mloza</groupId>
<artifactId>swagger-ui</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>15</maven.compiler.source>
<maven.compiler.target>15</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
</project>
view raw pom.xml hosted with ❤ by GitHub

Następnie możemy stworzyć przykładowe endpointy. Dla uproszczenia całą aplikację umieściłem w jednej klasie. Wygląda ona jak poniżej.

package pl.mloza;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import pl.mloza.database.Entry;
import pl.mloza.rest.AddEntryRequest;
import pl.mloza.rest.AddEntryResponse;
import pl.mloza.rest.ListEntryResponse;
import java.util.ArrayList;
import java.util.List;
@SpringBootApplication
@RestController
public class Main {
private final List<Entry> database = new ArrayList<>();
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
public Main() {
database.add(new Entry("one", "one"));
database.add(new Entry("two", "two"));
database.add(new Entry("three", "three"));
}
@GetMapping("/api/list")
public ListEntryResponse listObjects() {
return new ListEntryResponse(database);
}
@PostMapping("/api/add")
public AddEntryResponse addEntry(@RequestBody AddEntryRequest addEntryRequest) {
database.add(new Entry(addEntryRequest.getKey(), addEntryRequest.getValue()));
return new AddEntryResponse("Success");
}
}
view raw Main.java hosted with ❤ by GitHub

I to wszystko. Teraz wystarczy uruchomić aplikację i przejść pod adres: http://localhost:8080/swagger-ui/. Naszym oczom powinna się ukazać strona z listą endpointów, które możemy wywołać.

UI wygenerowany przez swaggera.

Dokumentacja kodu

Wspomniałem wcześniej, że możemy dokumentować kod za pomocą swaggera. Możemy dodać adnotacje do naszego kodu opisujące działanie poszczególnych endpointów. Swagger automatycznie pobierze treść adnotacji i dołączy je do UI. Zobaczymy to na przykładzie.

@Operation(
summary = "List all entries from database",
description = "Returns all entries that was saved to our database"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Entry was added to database"),
@ApiResponse(responseCode = "500", description = "Something went wrong, entry was not added")
})
@GetMapping("/api/list")
public ListEntryResponse listObjects() {
return new ListEntryResponse(database);
}
@Operation(
summary = "Add entry to database",
description = "Save entry to database. Keys and values can be duplicated."
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Entry was added to database"),
@ApiResponse(responseCode = "500", description = "Something went wrong, entry was not added")
})
@PostMapping("/api/add")
public AddEntryResponse addEntry(@RequestBody AddEntryRequest addEntryRequest) {
database.add(new Entry(addEntryRequest.getKey(), addEntryRequest.getValue()));
return new AddEntryResponse("Success");
}
@Operation(
summary = "Delete entry from database",
description = "Deletes entry from database. If entries are duplicated, we delete only one instance." +
" Returns deleted entry"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Entry was removed from database"),
@ApiResponse(responseCode = "500", description = "Something went wrong, entry was not added")
})
@DeleteMapping("/api/remove/{key}")
public RemoveEntryResponse deleteEntry(@PathVariable String key) {
Optional<Entry> entry = database.stream().filter(e -> e.getKey().equals(key)).findFirst();
return entry.map(e -> {
database.remove(e);
return new RemoveEntryResponse(e);
}).orElse(new RemoveEntryResponse());
}
view raw Api.java hosted with ❤ by GitHub

Widzimy 3 nowe adnotacje:

  • @Operation – Służy ona do opisu działania funkcji, summary pojawia się przy endpoincie (1 na screenshocie), descrption widoczne jest dopiero po kliknięciu i rozwinięciu endpointu (2 na screenshocie)
  • @ApiResponses i @ApiResponse – opisuje odpowiedzi, które może zwrócić serwis (3 na screenshocie)

Poniżej możecie zobaczyć jak to wygląda w przeglądarce.

Dokumentacja API

Poza podanymi przez nas opisami widzimy również model danych, których oczekuje serwis oraz tych, które zostaną zwrócone w odpowiedzi (odpowiednio 4 i 5 na obrazku). Klikając przycisk Execute możemy wywołać zapytanie do serwisu. Poniżej zostanie wyświetlona odpowiedź, którą zwróci serwis.

Konfiguracja Swaggera

Aby zmienić domyślne opisy na początku strony, musimy stworzyć bean z konfiguracją swaggera. Najprostsza konfiguracja może wyglądać jak poniżej.

@Configuration
public class SwaggerConfiguration {
public ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("API Demo")
.description("Demo application API")
.version("1.0.0")
.build();
}
@Bean
public Docket docket() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.enable(true)
.select()
.paths(PathSelectors.any())
.build();
}
}

Podsumowanie

Swagger umożliwia nam szybkie stworzenie UI do interakcji z naszą aplikacją oraz dokumentacji poszczególnych endpointów. Może być wykorzystywany do testowania lub gdy potrzebujemy czasu do czasu podjąć jakąś interakcję z aplikacją. Możemy też w ten sposób wystawić API dla frontendu, dzięki temu będą wiedzieli jakie operacje mogą wykonać na webserwisie. Swagger udostępnia również narzędzia do generowania kodu klienta i stubu dla serwera, jednak z tego jeszcze nie korzystałem. Jeśli mieliście okazję tego używać, daj znać w komentarzach jak się z tym pracuje ?

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *