Найти в Дзене

REST API на максималках

REST API на максималках

Обсудили в клубе тему, что реально можно автоматизировать на сервере, если у вас уже есть openapi-схема и наговорили на целый пост. А если схемы нет, то причины ниже, могут убедить вас или ваших коллег генерировать схему не по обработчикам, а наоборот.

Для начала нужны генераторы кода на базе openapi-схемы, таких в каждой экосистема по несколько штук как минимум. Как они помогают?

На базовом уровне генераторы просто создают DTO, которые вы сами парсите и валидируете вручную:

router.POST("/loginJSON", func(c *gin.Context) {

var json Login // Login сгенерирован

if err := c.ShouldBindJSON(&json); err != nil {

c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})

return

})

Это уже хорошая помощь от наличия спеки, но все еще очень много рукопашки и отсутствие контроля, того, что обработчики написаны правильно. Потому что одно дело сгенерировать структуры, а другое правильно (в соответствии со спекой openapi) их использовать в нужных местах. В общем что еще хотелось бы:

⁃ Валидацию запроса по схеме

⁃ Биндинг JSON → объект

⁃ Проверку ответа и статусов

⁃ Соответствие маршрутов и сигнатур контроллеров контракту

Только в этом случае, мы получим 100% пользу от наличия openapi схемы с максимальной автоматизацией всей рутины.

На практике же очень часто проверка ответа сводится к тестам, где JSON просто парсят и изучают его внутреннюю структуру вручную: сравнивают поля, типы, значения. В лучшем случае подключают валидацию по JSON Schema в тестах. Это по сути всё — ручная работа и проверки только на этапе выполнения тестов, без статических гарантий, подсказок редактора и без встроенного контроля на уровне фреймворка.

Полная генерация

Такое возможно только в случае наличия генераторов кода, которые глубоко интегрированы с фреймворком и умеют навешивать всю эту механику автоматически. Как минимум - иметь адаптер к конкретному фреймворку. К счастью, это есть плюс-минус во всех популярных экосистемах, но другой вопрос - знаете ли вы об этом и используете ли.

Давайте для примера возьмем Java и Spring Boot, где подобные задачи решаются давно и хорошо. В Spring Boot обычно используют OpenAPI Generator - он по спецификации генерирует интерфейсы контроллеров и модели (DTO). Вот пример интерфейса, который он генерирует:

public interface LoginApi {

@PostMapping("/login")

ResponseEntity<LoginResponse> login(@Valid @RequestBody LoginRequest request);

}

⁃ LoginRequest / LoginResponse — сгенерированные модели (с аннотациями валидации).

@RequestBody - Jackson сам парсит JSON → объект.

@Valid — проверка по аннотациям из схемы (400/422 уедут в хендлер ошибок).

И конкретная реализация

@RestController

class LoginController implements LoginApi {

@Override

public ResponseEntity<LoginResponse> login(LoginRequest req) {

var user = new User().id("u1").email(req.getEmail());

return ResponseEntity.ok(new LoginResponse().token("jwt...").user(user));

}

}

В итоге маршрут, сигнатура и типы подтягиваются из OpenAPI, модели тоже сгенерены. Мы пишем только логику внутри метода.

p.s. В ваших проектах используется полная генерация или частичная?

Ссылки: Телеграм | Youtube | VK