swagger-logo-bw

Aktualnie modną architekturą wśród systemów informatycznych są mikroserwisy. Najczęściej komunikują się one poprzez API REST’owe, które wykorzystuje notacje JSON. Często systemy te składają się z wielu mikroserwisów, które rozwijane są poprzez różne teamy w firmie. Jednym ze sposobów komunikacji pomiędzy teamami jest dokumentowanie całego API REST’owego. Narzędziem, które bardzo ułatwia dokumentowanie naszego API jest Swagger.

1. Maven dependencies

Zacznijmy od dodania zależności mavenowych. Pierwsza odpowiada za funkcje core Swagger czyli całą funkcjonalność, natomiast druga za GUI.

1
2
3
4
5
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
io.springfox springfox-swagger-ui 2.6.1 compile

2. Ustawienia Swaggera

Następnie utwórzmy sobie klasę z ustawieniami Swaggera.

@Configuration
@EnableSwagger2
public class SwaggerConfig {

@Bean
public Docket SwaggerApi() {
    return new Docket(DocumentationType.SWAGGER\_2)
            .groupName("codecouple-api")
            .apiInfo(apiInfo())
            .select()
            .apis(RequestHandlerSelectors.any())
            .paths(getSwaggerPaths())
            .build()
            .globalResponseMessage(RequestMethod.GET,
                    newArrayList(new ResponseMessageBuilder()
                            .code(500)
                            .message("500 message")
                            .responseModel(new ModelRef("Error"))
                            .build()));
}

private ApiInfo apiInfo() {
    return new ApiInfoBuilder()
            .title("Spring Demo with Swagger")
            .description("Spring Demo with Swagger")
            .contact(new Contact("Krzysztof Chrusciel",
                                 "http://codecouple.pl",
                                 "email@here.pl"))
            .license("License name here")
            .licenseUrl("URL to license")
            .version("1.0.1")
            .build();
}

private Predicate<String> getSwaggerPaths() {
    return or(
            regex("/api.\*"),
            regex("/test.\*"));
}

}

Adnotacja @EnableSwagger2 uruchamia możliwości Swaggera. Swagger dostracza bardzo fajne buildery do ustawień. Najważniejszym beanem jest Docket, w który znajdują się główne ustawienia. Natomiast w klasie ApiInfo możemy ustawić informacje na temat API.

3. Obsługiwane endpointy

W polu paths ustawiamy ścieżki endpointów, które będą obsługiwane przez Swaggera. Out-of-the-box metoda paths przyjmuje predykaty takie jak regex, ant, any, none. Predykatem domyślnym jest any. Możemy także używać wyrażeń regularnych:

private Predicate getSwaggerPaths() {
return or(
regex(“/api.*“),
regex(“/test.*“));
}

4. Globalne messages

W polu globalResponseMessage ustawiamy globalne messages dla różnych kodów statusów. W tym przykładzie dla wszystkich metod typu GET i kodu 500 zwracaj wiadomość “500 message“.

.globalResponseMessage(RequestMethod.GET,
newArrayList(new ResponseMessageBuilder()
.code(500)
.message(“500 message”)
.responseModel(new ModelRef(“Error”))
.build()));

Wszystkie ustawienia zostały zawarte w naszej klasie SwaggerConfig. Od teraz aplikacja Swaggera znajduje się pod adresem http://your_address/swagger-ui.html

swaggerui

5. Dokumentowanie API

Możemy teraz zacząć dokumentować nasze API. Zacznijmy od dodania pierwszego endpointa:

@GetMapping(value = “/api/book/{id}”, produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody Book getBooksByTitle(@PathVariable(required = true) Long id) {
return bookRepository.findOne(id);
}

Jak widzicie w przykładzie powyżej nie daliśmy żadnej specjalnej adnotacji natomiast Swagger skanuje classpath i odnajduje klasy adnotowane jako @Controller i automatycznie dodaje je do dokumentacji (chyba, że w ustawieniach zmieniliśmy paths i mają być skanowane na przykład tylko ścieżki, które w nazwie mają “test”). Domyślnie wyświetlany jest on jako nazwa metody getBooksByTitle, a adres to [nazwa_metody]Using[typ_meody], czyli getBooksByTitleUsingGET, http://your_address/swagger-ui.html#!/book-controller/getBooksByTitleUsingGET. Jeśli natomiast chcemy zmienić nazwę wyświetlaną w UI oraz adres to korzystamy z adnotacji @ApiOperation, gdzie value to nazwa w UI a nickname to adres URL.

@ApiOperation(value = “Add new book”, nickname = “Add new book”)

6. Specyficzne odpowiedzi dla statusów HTTP

Możemy także określić specyficzne odpowiedzi dla statusów HTTP:

@ApiResponses(value = {
@ApiResponse(code = 200, message = “Success”, response = Book.class),
@ApiResponse(code = 401, message = “Unauthorized”),
@ApiResponse(code = 403, message = “Forbidden”),
@ApiResponse(code = 404, message = “Not Found”),
@ApiResponse(code = 500, message = “Failure”)}) // Swagger annotation

7. Opis parametrów

W przypadku, gdy nasz endpoint przyjmuje parametr możemy go udokumentować poprzez adnotacje @ApiImplicitParams:

@ApiOperation(value = “Get book by id”, nickname = “Get book by id”)
@ApiImplicitParams({
@ApiImplicitParam(name = “id”, value = “Book’s id”, required = true, dataType = “long”, paramType = “path”, defaultValue=”1”)
})
@GetMapping(value = “/api/book/{id}”, produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody Book getBooksByTitle(@PathVariable(required = true) Long id) {
return bookRepository.findOne(id);
}

swaggeruiparameter

8. Więcej

API Swaggera jest bardzo rozbudowane i pozwala w bardzo prosty sposób na dokumentację API. Jeśli chcecie poczytać więcej zapraszam TUTAJ.