Swagger2/lib/Mojolicious/Command/swagger2.pm
package Mojolicious::Command::swagger2;
use Mojo::Base 'Mojolicious::Command';
use Mojo::Util;
use Swagger2;
my $app = __PACKAGE__;
# used in tests
our $OUT = \*STDOUT;
has description => 'Interface with Swagger2.';
has usage => <<"HERE";
Usage:
# Make a request to a Swagger server
@{[__PACKAGE__->_usage('client')]}
# Edit an API file in your browser
# This command also takes whatever option "morbo" takes
@{[__PACKAGE__->_usage('edit')]}
# Write POD to STDOUT
@{[__PACKAGE__->_usage('pod')]}
# Run perldoc on the generated POD
@{[__PACKAGE__->_usage('perldoc')]}
# Validate an API file
@{[__PACKAGE__->_usage('validate')]}
HERE
sub run {
my $self = shift;
my $action = shift || 'unknown';
my $code = $self->can("_action_$action");
die $self->usage unless $code;
$self->$code(@_);
}
sub _action_client {
my ($self, $file, @args) = @_;
unshift @args, $file if $ENV{SWAGGER_API_FILE};
$ENV{SWAGGER_COERCE_VALUES} //= 1;
my $method = shift @args;
my $args = {};
my $base_url = $ENV{SWAGGER_BASE_URL};
my $i = 0;
return print $OUT $self->_usage_client unless $ENV{SWAGGER_API_FILE} ||= $file;
return print $OUT $self->_documentation_for('') if !$method or $method =~ /\W/;
require Swagger2::Client;
my $client = Swagger2::Client->generate($ENV{SWAGGER_API_FILE});
for (@args) {
return $self->_documentation_for($method) if $_ eq 'help';
$base_url = $args[$i + 1] if $_ eq '-b';
$args = Mojo::JSON::decode_json($args[0]) if /^\{/;
$args->{$1} = $2 if /^(\w+)=(.*)/;
$i++;
}
$client->base_url->parse($base_url) if $base_url;
eval {
my $res = $client->$method($args);
print $OUT $res->json ? Mojo::Util::dumper($res->json) : $res->body;
1;
} or do {
my $e = $@;
$e =~ s! at .* line.*!!s;
warn "ERROR! $e\n";
};
}
sub _action_edit {
my ($self, $file, @args) = @_;
unshift @args, $file if $ENV{SWAGGER_API_FILE};
$ENV{SWAGGER_API_FILE} ||= $file || '';
$ENV{SWAGGER_LOAD_EDITOR} = 1;
$file ||= __FILE__;
require Swagger2::Editor;
system 'morbo', -w => $file, @args, $INC{'Swagger2/Editor.pm'};
}
sub _action_perldoc {
my ($self, $file) = @_;
die $self->_usage('perldoc'), "\n" unless $file;
require Mojo::Asset::File;
my $asset = Mojo::Asset::File->new;
$asset->add_chunk(Swagger2->new($file)->pod->to_string);
system perldoc => $asset->path;
}
sub _action_pod {
my ($self, $file) = @_;
die $self->_usage('pod'), "\n" unless $file;
print $OUT Swagger2->new($file)->pod->to_string;
}
sub _action_validate {
my ($self, $file) = @_;
my @errors;
die $self->_usage('validate'), "\n" unless $file;
@errors = Swagger2->new($file)->validate;
unless (@errors) {
print $OUT "$file is valid.\n";
return;
}
for my $e (@errors) {
print $OUT "$e\n";
}
}
sub _documentation_for {
my ($self, $needle) = @_;
my $pod = Swagger2->new($ENV{SWAGGER_API_FILE})->pod;
my $paths = $pod->{api_spec}->get('/paths') || {};
my @methods;
for my $path (sort keys %$paths) {
for my $method (sort keys %{$paths->{$path}}) {
push @methods, $paths->{$path}{$method}{operationId} || join ' ', $method, $path;
delete $paths->{$path}{$method} unless $methods[-1] eq $needle;
}
delete $paths->{$path} unless %{$paths->{$path}};
}
unless ($needle) {
print $OUT "$_\n" for sort @methods;
return;
}
require Pod::Simple;
my $pod_text = Pod::Text->new;
$pod_text->output_fh($OUT);
$pod_text->parse_string_document($pod->_paths_to_string);
}
sub _usage {
my $self = shift;
return "Usage: mojo swagger2 edit" if $_[0] eq 'edit';
return "Usage: mojo swagger2 perldoc path/to/spec.json" if $_[0] eq 'perldoc';
return "Usage: mojo swagger2 pod path/to/spec.json" if $_[0] eq 'pod';
return "Usage: mojo swagger2 validate path/to/spec.json" if $_[0] eq 'validate';
return "Usage: mojo swagger2 client path/to/spec.json <method> [args]" if $_[0] eq 'client';
die "No usage for '@_'";
}
sub _usage_client {
my $self = shift;
return <<HERE;
Usage:
# Call a method with arguments
mojo swagger2 client path/to/spec.json <method> [args]
# List methods
mojo swagger2 client path/to/spec.json
# Get documentation for a method
mojo swagger2 client path/to/spec.json <method> help
# Specify spec and/or base URL from environment.
# Useful for shell wrappers
SWAGGER_API_FILE=path/to/spec.json mojo swagger2 client <method>
SWAGGER_BASE_URL=https://example.com/1.0 mojo swagger2 client <method>
# Example arguments
mojo swagger2 client path/to/spec.json list_pets '{"limit":10}'
mojo swagger2 client path/to/spec.json list_pets limit=10 owner=joe
mojo swagger2 client path/to/spec.json -b https://example.com/1.0 list_pets limit=10 owner=joe
HERE
}
1;
=encoding utf8
=head1 NAME
Mojolicious::Command::swagger2 - mojo swagger2 command
=head1 DEPRECATION WARNING
See L<Swagger2>.
=head1 DESCRIPTION
L<Mojolicious::Command::swagger2> is a command for interfacing with L<Swagger2>.
=head1 SYNOPSIS
# Call a method with arguments
mojo swagger2 client path/to/spec.json <method> [args]
# List methods
mojo swagger2 client path/to/spec.json
# Get documentation for a method
mojo swagger2 client path/to/spec.json <method> help
# Specify spec and/or base URL from environment.
# Useful for shell wrappers
SWAGGER_API_FILE=path/to/spec.json mojo swagger2 client <method>
SWAGGER_BASE_URL=https://example.com/1.0 mojo swagger2 client <method>
# Example arguments
mojo swagger2 client path/to/spec.json list_pets '{"limit":10}'
mojo swagger2 client path/to/spec.json list_pets limit=10 owner=joe
mojo swagger2 client path/to/spec.json -b https://example.com/1.0 list_pets limit=10 owner=joe
=head1 ATTRIBUTES
=head2 description
Returns description of this command.
=head2 usage
Returns usage of this command.
=head1 METHODS
=head2 run
See L</SYNOPSIS>.
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2014-2015, Jan Henning Thorsen
This program is free software, you can redistribute it and/or modify it under
the terms of the Artistic License version 2.0.
=head1 AUTHOR
Jan Henning Thorsen - C<jhthorsen@cpan.org>
=cut