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. В ваших проектах используется полная генерация или частичная?