Учебник по Swagger UI и публикации документации

Swagger UI — это инструмент визуализации документации API, основанный на спецификации OpenAPI (ранее — спецификации Swagger). Он может преобразовывать документы спецификации API в интерактивный интерфейс документации API.

Через Swagger UI разработчики и пользователи могут:

  • Просматривать подробную информацию об API
  • Тестировать запросы API прямо в интерфейсе
  • Просматривать примеры запросов и ответов
  • Понимать функциональность и параметры различных конечных точек API

Преимущества Swagger UI

  1. Визуализация: Предоставляет чёткий и интуитивно понятный интерфейс документации API
  2. Интерактивность: Поддерживает онлайн-тестирование API без дополнительных инструментов
  3. Обновления в реальном времени: Документация автоматически обновляется после изменений кода
  4. Стандартизация: На основе спецификации OpenAPI, поддержание согласованности
  5. Кросс-языковая поддержка: Применимо к различным языкам программирования и фреймворкам

Интеграция Swagger UI

1. Интеграция в проект Spring Boot

Добавьте зависимости

Вpom.xmlДобавьте следующие зависимости:

Пример

<!-- Springfox Swagger2 -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>3.0.0</version>
</dependency>

<!-- Springfox Swagger UI -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>3.0.0</version>
</dependency>

Или используйте SpringDoc OpenAPI:

Пример

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-ui</artifactId>
    <version>1.6.14</version>
</dependency>

Настройка Swagger

Пример

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.example.controller"))
                .paths(PathSelectors.any())
                .build()
                .apiInfo(apiInfo());
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Документация API")
                .description("Подробное описание API")
                .version("1.0.0")
                .contact(new Contact("Команда разработчиков", "https://example.com", "[email protected]"))
                .build();
    }
}

Для SpringDoc OpenAPI:

Пример

import org.springdoc.core.GroupedOpenApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.Contact;

@Configuration
public class SwaggerConfig {
    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI()
                .info(new Info()
                        .title("Документация API")
                        .version("1.0.0")
                        .description("Подробное описание API")
                        .contact(new Contact()
                                .name("Команда разработчиков")
                                .email("[email protected]")
                                .url("https://example.com")));
    }

    @Bean
    public GroupedOpenApi publicApi() {
        return GroupedOpenApi.builder()
                .group("public-apis")
                .pathsToMatch("/api/**")
                .build();
    }
}

2. Интеграция в проект Node.js Express

Установите зависимости

npm install swagger-jsdoc swagger-ui-express --save

Настройка Swagger

Пример

const express = require('express');
const swaggerJsDoc = require('swagger-jsdoc');
const swaggerUi = require('swagger-ui-express');

const app = express();

// Конфигурация Swagger
const swaggerOptions = {
  определение: {
    openapi: '3.0.0',
    информация: {
      title: 'Документация API',
      version: '1.0.0',
      description: 'Подробное описание API',
      contact: {
        name: 'Команда разработки',
        email: '[email protected]',
        url: 'https://example.com'
      }
    },
    servers: [
      {
        url: 'http://localhost:3000',
        description: 'Сервер разработки'
      }
    ]
  },
  apis: ['./routes/*.js'] // Путь к файлу маршрута API
};

const swaggerDocs = swaggerJsDoc(swaggerOptions);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocs));

// ... другие маршруты и промежуточное ПО

app.listen(3000, () => {
  console.log('Сервер запущен по адресу http://localhost:3000');
  console.log('Документация API доступна по адресу http://localhost:3000/api-docs');
});

3. Использование в проекте Python FastAPI

FastAPI по умолчанию интегрирует Swagger UI:

Пример

from fastapi import FastAPI

app = FastAPI(
    title="Документация API",
    description="Подробное описание API",
    version="1.0.0",
    contact={
        "name": "Команда разработки",
        "email": "[email protected]",
        "url": "https://example.com",
    },
)

@app.get("/")
async def root():
    return {"message": "Hello World"}

Swagger UI по умолчанию доступен по пути /docs. Вы можете просмотреть документацию, перейдя по адресу http://localhost:8000/docs.

Подробнее см.:Интерактивная документация API FastAPI


Написание документации API

1. Аннотации документации API в проекте Spring Boot

Пример

import io.swagger.annotations.*;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/users")
@Api(tags = "Управление пользователями")
public class UserController {

    @ApiOperation(value = "Получить список пользователей", notes = "Получить всю информацию о пользователях с пагинацией")
    @ApiResponses({
        @ApiResponse(code = 200, message = "Успешно"),
        @ApiResponse(code = 400, message = "Некорректные параметры запроса"),
        @ApiResponse(code = 500, message = "Внутренняя ошибка сервера")
    })
    @GetMapping("/")
    public Page<User> getUsers(
            @ApiParam(value = "Номер страницы", required = true) @RequestParam int page,
            @ApiParam(value = "Количество записей на странице", required = true) @RequestParam int size) {
        // Бизнес-логика
        return userService.getUsers(page, size);
    }

    @ApiOperation(value = "Получить одного пользователя", notes = "Получить информацию о пользователе по ID")
    @GetMapping("/{id}")
    public User getUser(
            @ApiParam(value = "ID пользователя", required = true) @PathVariable Long id) {
        // Бизнес-логика
        return userService.getUser(id);
    }

    @ApiOperation(value = "Создать пользователя", notes = "Создать нового пользователя")
    @PostMapping("/")
    public User createUser(
            @ApiParam(value = "Информация о пользователе", required = true) @RequestBody UserDTO userDTO) {
        // Бизнес-логика
        return userService.createUser(userDTO);
    }
}

Для SpringDoc OpenAPI:

Пример

import io.swagger.v3.oas.annotations.*;
import io.swagger.v3.oas.annotations.media.*;
import io.swagger.v3.oas.annotations.responses.*;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/users")
@Tag(name = "Управление пользователями", description = "API, связанные с пользователями")
public class UserController {

    @Действие(
        summary = "Получить список пользователей",
        description = "Получить всю информацию о пользователях с пагинацией"
    )
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "Успешно"),
        @ApiResponse(responseCode = "400", description = "Недопустимые параметры запроса"),
        @ApiResponse(responseCode = "500", description = "Внутренняя ошибка сервера")
    })
    @GetMapping("/")
    public Page<User> getUsers(
            @Parameter(description = "Номер страницы", required = true) @RequestParam int page,
            @Parameter(description = "Количество записей на странице", required = true) @RequestParam int size) {
        // Бизнес-логика
        return userService.getUsers(page, size);
    }
}

2. Комментарии к документации API в проекте Node.js Express

Пример

/**
 * @swagger
 * /api/users:
 * get:
* summary: Получить список пользователей
* description: Получить всю информацию о пользователях с постраничной разбивкой
* tags: [Управление пользователями]
 * parameters:
 * - in: query
 * name: page
 * schema:
 * type: integer
 * required: true
* description: Номер страницы
 * - in: query
 * name: size
 * schema:
 * type: integer
 * required: true
* description: Количество записей на странице
 * responses:
 *       200:
* description: Успешно
 * content:
 * application/json:
 * schema:
 * type: object
 * properties:
 * data:
 * type: array
 * items:
 * $ref: '#/components/schemas/User'
 * total:
 * type: integer
 *       400:
* description: Недопустимые параметры запроса
 *       500:
* description: Внутренняя ошибка сервера
 */

router.get('/users', (req, res) => {
  // Бизнес-логика
});

/**
 * @swagger
 * components:
 * schemas:
 * User:
 * type: object
 * required:
 * - name
 * - email
 * properties:
 * id:
 * type: integer
* description: ID пользователя
 * name:
 * type: string
* description: Имя пользователя
 * email:
 * type: string
 * format: email
* description: Электронная почта пользователя
 */

3. Документация API в проекте Python FastAPI

Пример

from fastapi import FastAPI, Query, Path
from pydantic import BaseModel
from typing import List, Optional

app = FastAPI(title="API управления пользователями")

class User(BaseModel):
    id: int
    name: str
    email: str
   
    class Config:
        schema_extra = {
            "example": {
                "id": 1,
                "name": "Чжан Сань",
                "email": "[email protected]"
            }
        }

@app.get(
    "/api/users/",
    summary="Получить список пользователей",
    description="Получить всю информацию о пользователях с пагинацией",
    response_model=List[User],
    tags=["Управление пользователями"]
)
async def get_users(
    page: int = Query(..., description="Номер страницы", ge=1),
    size: int = Query(..., description="Количество записей на странице", ge=1, le=100)
):
    # Бизнес-логика
    return [
        {"id": 1, "name": "Чжан Сан", "email": "[email protected]"},
        {"id": 2, "name": "Ли Сы", "email": "[email protected]"}
    ]

@app.get(
    "/api/users/{user_id}",
    summary="Получить одного пользователя",
    description="Получить информацию о пользователе по ID",
    response_model=User,
    tags=["Управление пользователями"]
)
async def get_user(
    user_id: int = Путь(..., описание="ID пользователя", ge=1)
):
    # Бизнес-логика
    return {"id": user_id, "name": "Чжан Сань", "email": "[email protected]"}

Настройка Swagger UI

1. Пользовательская конфигурация Spring Boot

Пример

@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2)
            .select()
            .apis(RequestHandlerSelectors.basePackage("com.example.controller"))
            .paths(PathSelectors.regex("/api/.*"))
            .build()
            .apiInfo(apiInfo())
            .useDefaultResponseMessages(false)  // Отключить стандартные сообщения ответов
            .globalResponseMessage(RequestMethod.GET, globalResponses())  // Пользовательские глобальные сообщения ответов
            .securitySchemes(Arrays.asList(apiKey()))  // Настроить аутентификацию безопасности
            .securityContexts(Arrays.asList(securityContext()));  // Настроить контекст безопасности
}

private List<ResponseMessage> globalResponses() {
    return Arrays.asList(
            new ResponseMessageBuilder().code(200).message("Успех").build(),
            new ResponseMessageBuilder().code(400).message("Недопустимые параметры запроса").build(),
            new ResponseMessageBuilder().code(401).message("Неавторизован").build(),
            new ResponseMessageBuilder().code(403).message("Доступ запрещён").build(),
            new ResponseMessageBuilder().code(500).message("Внутренняя ошибка сервера").build()
    );
}

private ApiKey apiKey() {
    return new ApiKey("JWT", "Authorization", "header");
}

private SecurityContext securityContext() {
    return SecurityContext.builder()
            .securityReferences(defaultAuth())
            .forPaths(PathSelectors.regex("/api/.*"))
            .build();
}

private List<SecurityReference> defaultAuth() {
    AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
    AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
    authorizationScopes[0] = authorizationScope;
    return Arrays.asList(new SecurityReference("JWT", authorizationScopes));
}

2. Пользовательская конфигурация Express

Пример

const options = {
  customCss: '.swagger-ui .topbar { display: none }',  // Пользовательский CSS
  customSiteTitle: "Центр документации API",  // Заголовок страницы
  customfavIcon: "/favicon.png",  // Пользовательская иконка
  swaggerOptions: {
    persistAuthorization: true,  // Сохранять информацию об авторизации
    docExpansion: 'none',  // Свернуть все интерфейсы по умолчанию
    tagsSorter: 'alpha',   // Сортировать теги по алфавиту
    operationsSorter: 'alpha', // Сортировать операции по алфавиту
    defaultModelsExpandDepth: -1, // Скрыть модели
    filter: true,  // Включить фильтрацию
  }
};

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocs, options));

3. Пользовательская конфигурация FastAPI

Пример

from fastapi import FastAPI
from fastapi.openapi.docs import get_swagger_ui_html
from fastapi.staticfiles import StaticFiles

app = FastAPI(
    title="Документация по интерфейсу API",
    docs_url=None,  # Отключить стандартный Swagger UI
)

app.mount("/static", StaticFiles(directory="static"), name="static")

@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
    return get_swagger_ui_html(
        openapi_url=app.openapi_url,
        title=app.title + " - Документация API",
        oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
        swagger_js_url="/static/swagger-ui-bundle.js",
        swagger_css_url="/static/swagger-ui.css",
        swagger_favicon_url="/static/favicon.png",
        swagger_ui_parameters={
            "docExpansion": "none",
            "defaultModelsExpandDepth": -1,
            "filter": True,
        }
    )

Публикация документации

1. Внутренняя публикация

Для использования внутри команды вы можете напрямую открыть Swagger UI в приложении:

  • Spring Boot: http://your-app-host:port/swagger-ui/index.html
  • Express: http://your-app-host:port/api-docs
  • FastAPI: http://your-app-host:port/docs

2. Генерация статической документации

Используйте Swagger Codegen для создания статической документации

# 安装 Swagger Codegen CLI
wget https://repo1.maven.org/maven2/io/swagger/codegen/v3/swagger-codegen-cli/3.0.35/swagger-codegen-cli-3.0.35.jar -O swagger-codegen-cli.jar

# 生成静态 HTML 文档
java -jar swagger-codegen-cli.jar generate -i http://your-app-host:port/v3/api-docs -l html2 -o ./api-docs

Используйте Redoc для создания статической документации

# 安装 redoc-cli
npm install -g redoc-cli

# 生成静态 HTML 文档
redoc-cli bundle http://your-app-host:port/v3/api-docs -o ./api-docs/index.html

3. Интеграция в CI/CD-конвейер

Добавьте этапы генерации и публикации документации в CI/CD-конвейер:

Пример Jenkins Pipeline

Пример

pipeline {
    agent any
   
    stages {
        // ... другие этапы сборки и тестирования
       
        stage('Генерация документации API') {
            steps {
                sh 'java -jar swagger-codegen-cli.jar generate -i http://your-app-host:port/v3/api-docs -l html2 -o ./api-docs'
            }
        }
       
        stage('Публикация документации') {
            steps {
                // Публикация на статическом файловом сервере Nginx
                sh 'rsync -avz --delete ./api-docs/ user@doc-server:/var/www/api-docs/'
               
                // Или опубликовать в объектном хранилище (например, AWS S3)
                sh 'aws s3 sync ./api-docs/ s3://your-bucket/api-docs/ --delete'
            }
        }
    }
}

Пример рабочего процесса GitHub Actions

Пример

name: Генерация и развертывание документации API

на:
  push:
    branches: [ main ]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
   
    steps:
    - uses: actions/checkout@v2
   
    - name: Настроить JDK
      uses: actions/setup-java@v2
      with:
        distribution: 'adopt'
        java-version: '11'
   
    - name: Сборка приложения
      run: ./mvnw clean package
   
    - name: Запуск приложения
      run: |
        java -jar target/your-app.jar &
        sleep 30# Ожидание запуска приложения
   
    - name: Генерация документации API
      run: |
        wget -q https://repo1.maven.org/maven2/io/swagger/codegen/v3/swagger-codegen-cli/3.0.35/swagger-codegen-cli-3.0.35.jar -O swagger-codegen-cli.jar
        java -jar swagger-codegen-cli.jar generate -i http://localhost:8080/v3/api-docs -l html2 -o ./api-docs
   
    - name: Развертывание на GitHub Pages
      uses: JamesIves/github-pages-deploy-action@4.1.5
      with:
        branch: gh-pages
        folder: api-docs

4. Использование платформы управления документацией API

Помимо самостоятельного развертывания, вы также можете использовать профессиональные платформы управления документацией API:

  • Swagger Hub: Предоставляет услуги хостинга для проектирования API и документации
  • Postman: Позволяет тестировать API, а также публиковать документацию API
  • ReadMe.io: Предоставляет комплексное управление документацией API и портал для разработчиков
  • Stoplight: Предоставляет инструменты для проектирования, документирования и управления API

5. Развертывание Swagger UI с помощью Docker

Пример

FROM swaggerapi/swagger-ui:latest

# Установка переменных окружения
ENV SWAGGER_JSON=/swagger/openapi.json
ENV BASE_URL=/api-docs

# Копирование файла спецификации OpenAPI
COPY openapi.json /swagger/

# Открыть порт
EXPOSE 8080

# Запуск Swagger UI
CMD ["sh", "/usr/share/nginx/docker-run.sh"]

Сборка и запуск:

docker build -t my-swagger-ui .
docker run -p 8080:8080 my-swagger-ui

Доступ: http://localhost:8080/api-docs


Лучшие практики

1. Стандарты документации

  • Будьте кратки и понятны: Описания должны быть краткими и по существу
  • Управление группами: Используйте теги для логической группировки API
  • Приводите примеры: Приводите примеры запросов и ответов
  • Стандартизируйте обработку ошибок: Стандартизируйте формат ответов об ошибках и коды состояния
  • Управление версиями: Четко указывайте информацию о версии API в документации

2. Конфигурация безопасности

  • Обработка конфиденциальной информации: Не раскрывайте конфиденциальную информацию в документации
  • Конфигурация производственной среды: При необходимости отключите или ограничьте доступ к документации в производственной среде
  • Механизм аутентификации: Настройте аутентификацию для доступа к документации

Пример

// Конфигурация Spring Boot для отключения Swagger в рабочей среде
@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2)
            .enable(!environment.acceptsProfiles(Profiles.of("prod")))
            // ... другие конфигурации
}

3. Автоматизированное тестирование

Объедините документацию и тесты, чтобы содержимое документации оставалось согласованным с фактическим поведением API:

Пример

// Тестирование Spring Boot с REST Assured и Swagger
@Test
public void validateSwaggerDocumentation() {
    // Получить Swagger JSON
    String swaggerJson = given()
            .когда()
            .get("/v3/api-docs")
            .затем()
            .statusCode(200)
            .extract().asString();
   
    // Проверить документацию Swagger
    OpenAPI openAPI = new OpenAPIParser().readContents(swaggerJson, null, null).getOpenAPI();
    assertNotNull(openAPI);
   
    // Проверить, существует ли конкретный эндпоинт в документации
    assertNotNull(openAPI.getPaths().get("/api/users"));
}

Устранение распространённых проблем

1. Swagger UI не отображается или ошибки при загрузке

  • Проверьте версии зависимостей: Убедитесь, что версии зависимостей совместимы
  • Проверьте классы конфигурации: Убедитесь, что классы конфигурации зарегистрированы правильно
  • Проверьте сопоставления путей: Убедитесь, что сопоставления путей верны
  • Проверьте настройки cross-origin: Если доступ осуществляется из другого источника, убедитесь, что конфигурация CORS верна

2. Неполная информация об API

  • Проверьте аннотации: убедитесь, что все необходимые аннотации добавлены
  • Проверьте пути сканирования пакетов: убедитесь, что пути сканирования включают все контроллеры
  • Проверьте классы моделей: убедитесь, что классы моделей имеют корректные описания

3. Проблемы безопасности в производственной среде

Настройте производственную среду, чтобы отключить или защитить документацию:

# application-prod.properties
springdoc.swagger-ui.enabled=false
springdoc.api-docs.enabled=false

Или защитите с помощью базовой аутентификации:

Пример

@Configuration
@Profile("prod")
public class SwaggerSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.requestMatchers()
            .antMatchers("/swagger-ui/**", "/v3/api-docs/**")
            .и()
            .authorizeRequests()
            .anyRequest().hasRole("ADMIN")
            .и()
            .httpBasic();
    }
}
```

Итог

Swagger UI — мощный инструмент документирования API. При правильной настройке и использовании он может значительно повысить удобство использования API и эффективность разработки. В этом руководстве рассматриваются основные концепции Swagger UI, методы интеграции, написание документации, пользовательская настройка, публикация документации и лучшие практики — в надежде, что это будет полезно для вашей работы с документацией API.

Запомните следующие ключевые моменты:

  1. Выберите метод интеграции Swagger, подходящий для технологического стека вашего проекта
  2. Тщательно проектируйте и пишите аннотации или комментарии для документации API
  3. Настраивайте интерфейс Swagger UI по мере необходимости
  4. Выберите подходящий способ публикации документации
  5. Следуйте лучшим практикам, чтобы обеспечить точность и безопасность документации

Правильно используя Swagger UI, вы можете предоставить профессиональную, интерактивную документацию для вашего API, что сделает ваш API более понятным и удобным в использовании.

Другие расширения