Пробуем OpenAPI + Mojolicious
В определенный момент при развитии API приложения приходишь к мысли о миграции на OpenAPI. И вот я подошел к такому же моменту “прозрения” :-D. Хочется удобного инструмента, и swagger кажется то что нужно. Но разобраться в том как это запускать и работать с ним не так чтобы совсем просто (впрочем и не сложно). Пишу этот пост для того чтобы документрировать свое продвижение по этому вопросу.
Итак, берем наш ящик с инструментами. В нем у нас Mojolicious и Mojolicious::Plugin::OpenAPI . Последний поставился у меня с 10-го раза, т.к. почему-то зависимости от JSON::Validator так просто не сработали. Но все же установился.
Генерим простую app у
mojo generate app SimpleAPI
Я люблю конфиг держать в JSON, таким образом его удобнее шарить между другими частями системы, поэтому мой startup получается такой:
sub startup { my $self = shift;
my $config = $self->plugin('JSONConfig');
$self->secrets($config->{secrets});
# Router my $r = $self->routes; $r->get('/')->to('Pets#welcome'); $self->plugin("OpenAPI" => {url => $self->home->rel_file("json/myapi.json")}); }
Я подключил спецификацию из файла json/myapi.json .
Он у меня почти из документации скопипачен
{ "swagger": "2.0", "info": { "version": "1.0", "title": "Some awesome API" }, "basePath": "/api", "paths": { "/pets": { "get": { "operationId": "getPets", "x-mojo-name": "get_pets", "x-mojo-to": "pets#list", "summary": "Finds pets in the system", "parameters": [ {"in": "query", "name": "age", "type": "integer"} ], "responses": { "200": { "description": "Pet response", "schema": { "type": "object", "properties": { "pets": { "type": "array", "items": { "type": "object" } } } } } } } } } }
Тут уже нужно курить ман по спецификации OpenAPI, на первом этапе нам важно знать как определить роут и контроллер. За это отвечают следующие опции:
basePath - за этим роутом лежит наш апи.
"paths": { "/pets" - это роут, к нему обращатся так: localhost:3000/api/pets
"x-mojo-to": "pets#list", - это указание на контроллер Pets.pm и метод list
В контроллере:
sub list { my $c = shift->openapi->valid_input or return;
my $spec = $c->openapi->spec;
my $input = $c->validation->output; # $output will be validated by the OpenAPI spec before rendered
my $output = {description => "kit-e-cat", age => $input->{age} }; $c->render(openapi => $output);
}
Вот пока и все. Но что мы уже имеем. Самое главное - это
1. Документация по методам (в спецификации)
2. Валидация ввода. Т.е. в нашем примере при обращении по урлу:
http://127.0.0.1:3000/api/pets?age=123
получим
{"age":123,"descriptionzz":"kit-e-cat"}
А если мы запросим не integer
http://127.0.0.1:3000/api/pets?age=qwe
то уже
{"errors":[{"message":"Expected integer - got string.","path":"\/age"}],"status":400}
И это прекрасно :). Дальше постараюсь рассказать об авторизации и построении SPA приложения на базе Vue.js











