Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Документация API: OpenAPI и Swagger UI

Фронтенд-разработчику или другой команде нужно знать, какие адреса есть у API, что они принимают и что возвращают. Такое описание принято делать в формате OpenAPI — это JSON-файл со списком маршрутов, параметров и моделей данных. По нему Swagger UI рисует страницу, где каждый запрос можно посмотреть и сразу выполнить. Для Javalin есть официальный плагин javalin-openapi: вы описываете обработчики аннотацией @OpenApi, а при компиляции обработчик аннотаций (annotation processor — программа, которая запускается вместе с компилятором) собирает из них спецификацию.

Зависимости

Номер версии плагина идёт вслед за Javalin: для Javalin 7.2.3 подходит плагин 7.2.3. В pom.xml добавьте свойство и две зависимости:

<!-- pom.xml -->
<properties>
    <!-- ... -->
    <javalin.openapi.version>7.2.3</javalin.openapi.version>
</properties>
 
<dependency>
    <groupId>io.javalin.community.openapi</groupId>
    <artifactId>javalin-openapi-plugin</artifactId>
    <version>${javalin.openapi.version}</version>
</dependency>
<dependency>
    <groupId>io.javalin.community.openapi</groupId>
    <artifactId>javalin-swagger-plugin</artifactId>
    <version>${javalin.openapi.version}</version>
</dependency>

А в настройки maven-compiler-plugin — сам обработчик аннотаций:

<!-- pom.xml -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.14.1</version>
    <configuration>
        <annotationProcessorPaths>
            <path>
                <groupId>io.javalin.community.openapi</groupId>
                <artifactId>openapi-annotation-processor</artifactId>
                <version>${javalin.openapi.version}</version>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>

Описание маршрутов

Аннотация ставится на метод контроллера. Все классы аннотаций лежат в пакете io.javalin.openapi:

// src/main/java/com/example/blog/PostController.java
@OpenApi(
        path = "/posts/{id}",
        methods = HttpMethod.GET,
        summary = "Пост по номеру",
        tags = "Посты",
        pathParams = @OpenApiParam(name = "id", type = Long.class, required = true),
        responses = {
                @OpenApiResponse(status = "200", content = @OpenApiContent(from = Post.class)),
                @OpenApiResponse(status = "404", description = "Пост не найден")
        }
)
public void getOne(Context ctx) {
    // код без изменений
}
 
@OpenApi(
        path = "/posts",
        methods = HttpMethod.POST,
        summary = "Создать пост",
        tags = "Посты",
        security = @OpenApiSecurity(name = "BasicAuth"),
        requestBody = @OpenApiRequestBody(content = @OpenApiContent(from = NewPost.class), required = true),
        responses = {
                @OpenApiResponse(status = "201", content = @OpenApiContent(from = Post.class)),
                @OpenApiResponse(status = "400", description = "Ошибка проверки данных"),
                @OpenApiResponse(status = "401", description = "Нужен вход")
        }
)
public void create(Context ctx) {
    // код без изменений
}

path и methods должны совпадать с настоящим маршрутом: плагин не сверяет их с apiBuilder. from = Post.class превращает запись в схему JSON, для списка пишут from = Post[].class. Так же опишите getAll и delete.

Подключение плагинов

// src/main/java/com/example/blog/Main.java
config.registerPlugin(new OpenApiPlugin(openapi -> {
    openapi.withDefinitionConfiguration((version, builder) -> {
        builder.info(info -> info.title("API блога").version("1.0.0"));
        builder.withBasicAuth("BasicAuth");
    });
}));
config.registerPlugin(new SwaggerPlugin());

OpenApiPlugin (пакет io.javalin.openapi.plugin) отдаёт спецификацию по адресу /openapi, SwaggerPlugin (io.javalin.openapi.plugin.swagger) — страницу /swagger. withBasicAuth("BasicAuth") объявляет схему входа, на которую ссылается @OpenApiSecurity. У адресов документации нет ролей, поэтому проверка Auth::check их пропускает.

Проверка

Выполните mvn compile exec:java и запросите спецификацию:

curl http://localhost:8080/openapi
{
  "openapi" : "3.1.0",
  "info" : {
    "title" : "API блога",
    "version" : "1.0.0"
  },
  ...
    "/posts/{id}" : {
      "get" : {
        "tags" : [ "Посты" ],
        "summary" : "Пост по номеру",
        "parameters" : [ {
          "name" : "id",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "integer",
            "format" : "int64"
          }
        } ],
  ...

Откройте http://localhost:8080/swagger в браузере: в группе «Посты» видны четыре запроса, внизу — схемы NewPost и Post. Кнопка Authorize принимает логин и пароль, а Try it out отправляет настоящий запрос к серверу.

Частая ошибка

Без блока annotationProcessorPaths проект компилируется без ошибок, но спецификация пустая:

{
  "info" : {
    "title" : "API блога",
    "version" : "1.0.0"
  },
  "components" : {
    "securitySchemes" : { ... },
    "schemas" : { }
  },
  "paths" : { }
}

В спецификации нет даже поля openapi с номером версии, и Swagger UI вместо списка запросов пишет Unable to render this definition: The provided definition does not specify a valid version field. Обработчик аннотаций кладёт файл target/classes/openapi-plugin/openapi-default.json — если его нет, проверьте настройки maven-compiler-plugin и пересоберите проект командой mvn clean compile.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.