Содержимое
Формат OpenAPI, конечно, интересный и довольно мощный (например, вы знали, что там есть наследование и полиморфизм?..) Но он всё-таки сложный. И объемный. Назвать его компактным никак нельзя. Но есть упрощение и для OpenAPI. Ну то есть, в каком смысле упрощение. По крайней мере, компактификация. Всё ближе к языку программирования, всё дальше от текстового описания. Это язык TypeSpec (https://typespec.io/) Выглядит примерно так: import "@typespec/http"; using TypeSpec.Http; // Определение моделей model Pet { name: string; age: int32; } model Store { name: string; address: Address; } model Address { street: string; city: string; } // Определение эндпоинтов @route("/pets") interface Pets { list(@query filter: string): Pet[]; create(@body pet: Pet): Pet; read(@path id: string): Pet; } @route("/stores") interface Stores { list(@query filter: string): Store[]; read(@path id: string): Store; } Что мы тут видим: — целевая генерация будет в http api (а может быть ещё protobuf, тут замена уже совсем простая) — заданы три модели: Pet, Store и Address; это вам не JSON-Schema, синтаксис проще и компактней. — заданы два эндпоинта: /pets и /stores, для первого -- три метода (получить список с возможностью указать фильтр в параметрах запроса; создать, передав JSON в теле запроса; получить один экземпляр по id, переданному в эндпоинте после /), для второго — два. На этом всё. Из этого кода генерится спека в OpenAPI (JSON-схема, .proto-файл), которую дальше уже можно использовать как обычно (а как обычно вы её используете? скорее всего, либо код из неё генерируете, либо для верификации написанного вручную кода в ходе автоматической проверки релиза). То есть, это такой DSL для OpenAPI. Язык тоже мощный, всё, что есть в OpenAPI и http, он поддерживает. Например, чтобы дописать тип аутентификации, нужно добавить строчку вроде @useAuth(BasicAuth) Чтобы добавить поля заголовка запроса и коды ответов, нужно описать операцию чуть подробнее: op read(@path petId: int32, @header ifMatch?: string): { @statusCode statusCode: 200; @header eTag: string; @body pet: Pet; } | { @statusCode statusCode: 404; }; Что ещё классного есть в TypeSpec — абстрактные паттерны. Например, вы можете определить паттерн фильтрации через параметры запроса для любого ресурса, и потом его использовать, меняя только модель: // Define abstraction for resource lifecyle op ResourceList<T>(@query filter: string): T[]; op ResourceRead<T>(@path id: string): T; @post op ResourceCreate<T>(...T): T; model Pet { name: string; age: int32; } @route("/pets") interface Pets { list is ResourceList<Pet>; create is ResourceCreate<Pet>; read is ResourceRead<Pet>; } Ну как вам? Смогли бы такой язык использовать? Или совсем жесть, и это только для программистов?