Gymterview
senior

Что такое подход API Design First?

API Design First (API-first) — подход к разработке, при котором спецификация API (контракт) создаётся до написания кода. Из спецификации автоматически генерируются серверные интерфейсы, клиентские SDK, документация и тесты.

API-first vs Code-first

Характеристика API-first (Design First) Code-first
Последовательность Спецификация -> Код Код -> Спецификация (генерируется)
Источник истины OpenAPI-спецификация Исходный код (аннотации)
Параллельная разработка Да (frontend и backend одновременно) Нет (frontend ждёт backend)
Согласованность Контракт фиксирован заранее Контракт может меняться неконтролируемо
Инструменты OpenAPI Generator, Swagger Codegen springdoc-openapi, Swagger annotations

Преимущества API-first

  • Параллельная разработка — frontend и backend работают одновременно.
  • Контракт как документация — спецификация всегда актуальна.
  • Автоматизированное тестирование — тесты генерируются на основе спецификации.
  • Генерация клиентских SDK для любого языка.
  • Раннее обнаружение ошибок — несовместимые изменения обнаруживаются на этапе проектирования.
Пример OpenAPI-спецификации
openapi: 3.0.3
info:
  title: User Service API
  version: 1.0.0
  description: API для управления пользователями

servers:
  - url: https://api.example.com/v1

paths:
  /users:
    get:
      operationId: getUsers
      summary: Получить список пользователей
      tags:
        - Users
      parameters:
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum: [ACTIVE, INACTIVE, BLOCKED]
        - name: page
          in: query
          schema:
            type: integer
            default: 0
        - name: size
          in: query
          schema:
            type: integer
            default: 20
      responses:
        '200':
          description: Список пользователей
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserPage'
    post:
      operationId: createUser
      summary: Создать пользователя
      tags:
        - Users
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserRequest'
      responses:
        '201':
          description: Пользователь создан
          headers:
            Location:
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserDto'
        '400':
          description: Ошибка валидации

components:
  schemas:
    CreateUserRequest:
      type: object
      required: [name, email]
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
        email:
          type: string
          format: email
        age:
          type: integer
          minimum: 18

    UserDto:
      type: object
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string
        email:
          type: string
        age:
          type: integer
        createdAt:
          type: string
          format: date-time

    UserPage:
      type: object
      properties:
        content:
          type: array
          items:
            $ref: '#/components/schemas/UserDto'
        totalElements:
          type: integer
          format: int64
        totalPages:
          type: integer

  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

security:
  - BearerAuth: []
Настройка генерации кода в Spring Boot (Maven)
<plugin>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-maven-plugin</artifactId>
    <version>7.5.0</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <inputSpec>${project.basedir}/src/main/resources/openapi/api.yaml</inputSpec>
                <generatorName>spring</generatorName>
                <apiPackage>com.example.api</apiPackage>
                <modelPackage>com.example.model</modelPackage>
                <configOptions>
                    <interfaceOnly>true</interfaceOnly>
                    <useSpringBoot3>true</useSpringBoot3>
                    <useTags>true</useTags>
                    <openApiNullable>false</openApiNullable>
                    <skipDefaultInterface>false</skipDefaultInterface>
                </configOptions>
            </configuration>
        </execution>
    </executions>
</plugin>

Сгенерированный интерфейс:

@Tag(name = "Users", description = "Управление пользователями")
@Generated("org.openapitools.codegen")
public interface UsersApi {

    @Operation(summary = "Получить список пользователей")
    @GetMapping(value = "/users", produces = "application/json")
    ResponseEntity<UserPage> getUsers(
        @RequestParam(required = false) String status,
        @RequestParam(defaultValue = "0") Integer page,
        @RequestParam(defaultValue = "20") Integer size
    );

    @Operation(summary = "Создать пользователя")
    @PostMapping(value = "/users", consumes = "application/json", produces = "application/json")
    ResponseEntity<UserDto> createUser(@Valid @RequestBody CreateUserRequest request);
}

Реализация:

@RestController
@RequiredArgsConstructor
public class UsersApiController implements UsersApi {

    private final UserService userService;

    @Override
    public ResponseEntity<UserPage> getUsers(String status, Integer page, Integer size) {
        UserPage users = userService.findAll(status, page, size);
        return ResponseEntity.ok(users);
    }

    @Override
    public ResponseEntity<UserDto> createUser(CreateUserRequest request) {
        UserDto created = userService.create(request);
        URI location = URI.create("/users/" + created.getId());
        return ResponseEntity.created(location).body(created);
    }
}

Частые ошибки

  • Генерация полного сервера вместо interfaceOnly — приводит к нечитаемому коду.
  • Редактирование сгенерированного кода вручную — изменения будут перезаписаны.
  • Расхождение спецификации и реализации — нужна CI/CD проверка (contract testing).

Как используется в 2026

  • API-first стал стандартом де-факто в крупных компаниях и микросервисных архитектурах.
  • OpenAPI Generator 7.x поддерживает Spring Boot 3.x, Jakarta EE, virtual threads.
  • Spectral и Redocly CLI используются для линтинга спецификаций в CI/CD.
  • AsyncAPI — аналог OpenAPI для асинхронных API (Kafka, RabbitMQ, WebSocket).

На собеседовании: нужно объяснить разницу между API-first и Code-first, назвать преимущества API-first (параллельная разработка, контракт как единый источник истины) и упомянуть interfaceOnly=true. Частая ошибка — не знать про OpenAPI Generator или путать его со Swagger Codegen.