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.