diff --git a/.gitignore b/.gitignore index c904ba4a5fe5..d55a8014a342 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,9 @@ samples/client/petstore/python/.projectile samples/client/petstore/python/.venv/ */.settings + +*.mustache~ +*.java~ +*.pm~ +*.xml~ +*.t~ \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PerlClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PerlClientCodegen.java index ddbd6c7e2170..27f39f11ed0d 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PerlClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PerlClientCodegen.java @@ -99,6 +99,9 @@ public class PerlClientCodegen extends DefaultCodegen implements CodegenConfig { supportingFiles.add(new SupportingFile("Configuration.mustache", ("lib/WWW/" + moduleName).replace('/', File.separatorChar), "Configuration.pm")); supportingFiles.add(new SupportingFile("BaseObject.mustache", ("lib/WWW/" + moduleName).replace('/', File.separatorChar), "Object/BaseObject.pm")); supportingFiles.add(new SupportingFile("ApiFactory.mustache", ("lib/WWW/" + moduleName).replace('/', File.separatorChar), "ApiFactory.pm")); + supportingFiles.add(new SupportingFile("Role.mustache", ("lib/WWW/" + moduleName).replace('/', File.separatorChar), "Role.pm")); + supportingFiles.add(new SupportingFile("AutoDoc.mustache", ("lib/WWW/" + moduleName + "/Role").replace('/', File.separatorChar), "AutoDoc.pm")); + supportingFiles.add(new SupportingFile("autodoc.script.mustache", ("bin/").replace('/', File.separatorChar), "autodoc")); } public CodegenType getTag() { diff --git a/modules/swagger-codegen/src/main/resources/perl/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/perl/ApiClient.mustache index 0cdb40325c54..bf1220912d20 100644 --- a/modules/swagger-codegen/src/main/resources/perl/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/perl/ApiClient.mustache @@ -20,7 +20,9 @@ use Module::Runtime qw(use_module); use WWW::{{moduleName}}::Configuration; -sub new +use base 'Class::Singleton'; + +sub _new_instance { my $class = shift; my (%args) = ( @@ -32,6 +34,8 @@ sub new return bless \%args, $class; } +sub _cfg {'WWW::{{moduleName}}::Configuration'} + # Set the user agent of the API client # # @param string $user_agent The user agent of the API client @@ -288,13 +292,15 @@ sub select_header_content_type # @return string API key with the prefix sub get_api_key_with_prefix { - my ($self, $api_key) = @_; - if ($WWW::{{moduleName}}::Configuration::api_key_prefix->{$api_key}) { - return $WWW::{{moduleName}}::Configuration::api_key_prefix->{$api_key}." ".$WWW::{{moduleName}}::Configuration::api_key->{$api_key}; - } else { - return $WWW::{{moduleName}}::Configuration::api_key->{$api_key}; - } -} + my ($self, $key_name) = @_; + + my $api_key = $WWW::{{moduleName}}::Configuration::api_key->{$key_name}; + + return unless $api_key; + + my $prefix = $WWW::{{moduleName}}::Configuration::api_key_prefix->{$key_name}; + return $prefix ? "$prefix $api_key" : $api_key; +} # update header and query param based on authentication setting # @@ -304,17 +310,8 @@ sub get_api_key_with_prefix sub update_params_for_auth { my ($self, $header_params, $query_params, $auth_settings) = @_; - # we can defer to the application - if ($self->{auth_setup_handler} && ref($self->{auth_setup_handler}) eq 'CODE') { - $self->{auth_setup_handler}->( api_client => $self, - header_params => $header_params, - query_params => $query_params, - auth_settings => $auth_settings, # presumably this won't be defined if we're doing it this way - ); - return; - } - - return if (!defined($auth_settings) || scalar(@$auth_settings) == 0); + return $self->_global_auth_setup($header_params, $query_params) + unless $auth_settings && @$auth_settings; # one endpoint can have more than 1 auth settings foreach my $auth (@$auth_settings) { @@ -327,10 +324,47 @@ sub update_params_for_auth { } {{/authMethods}} else { - # TODO show warning about security definition not found + # TODO show warning about security definition not found } } } +# The endpoint API class has not found any settings for auth. This may be deliberate, +# in which case update_params_for_auth() will be a no-op. But it may also be that the +# swagger spec does not describe the intended authorization. So we check in the config for any +# auth tokens and if we find any, we use them for all endpoints; +sub _global_auth_setup { + my ($self, $header_params, $query_params) = @_; + + my $tokens = $self->_cfg->get_tokens; + return unless keys %$tokens; + + # basic + if (my $uname = delete $tokens->{username}) { + my $pword = delete $tokens->{password}; + $header_params->{'Authorization'} = 'Basic '.encode_base64($uname.":".$pword); + } + + # oauth + if (my $access_token = delete $tokens->{access_token}) { + $header_params->{'Authorization'} = 'Bearer ' . $access_token; + } + + # other keys + foreach my $token_name (keys %$tokens) { + my $in = $tokens->{$token_name}->{in}; + my $token = $self->get_api_key_with_prefix($token_name); + if ($in eq 'head') { + $header_params->{$token_name} = $token; + } + elsif ($in eq 'query') { + $query_params->{$token_name} = $token; + } + else { + die "Don't know where to put token '$token_name' ('$in' is not 'head' or 'query')"; + } + } +} + 1; diff --git a/modules/swagger-codegen/src/main/resources/perl/ApiFactory.mustache b/modules/swagger-codegen/src/main/resources/perl/ApiFactory.mustache index fc309c91b9cf..fc119f7a9026 100644 --- a/modules/swagger-codegen/src/main/resources/perl/ApiFactory.mustache +++ b/modules/swagger-codegen/src/main/resources/perl/ApiFactory.mustache @@ -21,9 +21,7 @@ use WWW::{{moduleName}}::ApiClient; use WWW::{{moduleName}}::ApiFactory; - my $api_factory = WWW::{{moduleName}}::ApiFactory->new( base_url => 'http://petstore.swagger.io/v2', - ..., # other args for ApiClient constructor - ); + my $api_factory = WWW::{{moduleName}}::ApiFactory->new( ... ); # any args for ApiClient constructor # later... my $pet_api = $api_factory->get_api('Pet'); @@ -47,26 +45,16 @@ my %_apis = map { $_ =~ /^WWW::{{moduleName}}::(.*)$/; $1 => $_ } =head1 new() - All parameters are optional, and are passed to and stored on the api_client object. + Any parameters are optional, and are passed to and stored on the api_client object. - base_url: supply this to change the default base URL taken from the Swagger definition. + base_url: (optional) + supply this to change the default base URL taken from the Swagger definition. - auth_setup_handler: a coderef you can supply to set up authentication. - - The coderef receives a hashref with keys: api_client, query_params, header_params, auth_settings. - - my $api_factory = WWW::{{moduleName}}::ApiFactory->new( auth_setup_handler => \&setup_auth ); ); - - sub setup_auth { - my %p = @_; - $p{header_params}->{'X-SomeApp-FunkyKeyName'} = 'aaaaabbbbbcccccddddd'; - } - =cut sub new { my ($class, %p) = (shift, @_); - $p{api_client} = WWW::{{moduleName}}::ApiClient->new(%p); + $p{api_client} = WWW::{{moduleName}}::ApiClient->instance(%p); return bless \%p, $class; } @@ -95,4 +83,18 @@ sub get_api { sub api_client { $_[0]->{api_client} } +=head1 apis_available() +=cut + +sub apis_available { return map { $_ =~ s/Api$//; $_ } sort keys %_apis } + +=head1 classname_for() +=cut + +sub classname_for { + my ($self, $api_name) = @_; + return $_apis{"${api_name}Api"}; +} + + 1; diff --git a/modules/swagger-codegen/src/main/resources/perl/AutoDoc.mustache b/modules/swagger-codegen/src/main/resources/perl/AutoDoc.mustache new file mode 100644 index 000000000000..76da048b0693 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/perl/AutoDoc.mustache @@ -0,0 +1,427 @@ +package WWW::{{moduleName}}::Role::AutoDoc; +use List::MoreUtils qw(uniq); + +use Moose::Role; + +sub autodoc { + my ($self, $how) = @_; + + die "Unknown format '$how'" unless $how =~ /^(pod|wide|narrow)$/; + + $self->_printisa($how); + $self->_printmethods($how); + $self->_printattrs($how); + print "\n"; +} + +sub _printisa { + my ($self, $how) = @_; + my $meta = $self->meta; + + my $myclass = ref $self; + + my $super = join ', ', $meta->superclasses; + my @roles = $meta->calculate_all_roles; + #shift(@roles) if @roles > 1; # if > 1, the first is a composite, the rest are the roles + + my $isa = join ', ', grep {$_ ne $myclass} $meta->linearized_isa; + my $sub = join ', ', $meta->subclasses; + my $dsub = join ', ', $meta->direct_subclasses; + + my $app_name = $self->version_info->{app_name}; + my $app_version = $self->version_info->{app_version}; + my $generated_date = $self->version_info->{generated_date}; + my $generator_class = $self->version_info->{generator_class}; + + $~ = $how eq 'pod' ? 'INHERIT_POD' : 'INHERIT'; + write; + + my ($rolepkg, $role_reqs); + + foreach my $role (@roles) { + $rolepkg = $role->{package} || next; # some are anonymous, or something + next if $rolepkg eq 'WWW::{{moduleName}}::Role::AutoDoc'; + $role_reqs = join ', ', keys %{$role->{required_methods}}; + $role_reqs ||= ''; + $~ = $how eq 'pod' ? 'ROLES_POD' : 'ROLES'; + write; + } + + if ($how eq 'pod') { + $~ = 'ROLES_POD_CLOSE'; + write; + } + +# ----- format specs ----- + format INHERIT = + +@* - +$myclass + ISA: @* + $isa + Direct subclasses: @* + $dsub + All subclasses: @* + $sub + + Target API: @* @* + $app_name, $app_version + Generated on: @* + $generated_date + Generator class: @* + $generator_class + +. + format ROLES = + Composes: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~ + $rolepkg + requires: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~ + $role_reqs + ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~~ + $role_reqs +. + + format INHERIT_POD = +=head1 NAME + +@* +$myclass + +=head1 VERSION + +=head2 @* version: @* + $app_name, $app_version + +Automatically generated by the Perl Swagger Codegen project: + +=over 4 + +=item Build date: @* + $generated_date + +=item Build package: @* + $generator_class + +=item Codegen version: + + +=back + +=head1 INHERITANCE + +=head2 Base class(es) + +@* +$isa + +=head2 Direct subclasses + +@* +$dsub + +=head2 All subclasses + +@* +$sub + + +=head1 COMPOSITION + +@* composes the following roles: +$myclass + + +. + format ROLES_POD = +=head2 C<@*> + $rolepkg + +Requires: + +@* +$role_reqs + +. + format ROLES_POD_CLOSE = + + +. +# ----- / format specs ----- +} + +sub _printmethods { + my ($self, $how) = @_; + + if ($how eq 'narrow') { + print <_printmethod($_, $how) for uniq sort $self->meta->get_all_method_names; #$self->meta->get_method_list, + + if ($how eq 'pod') { + $~ = 'METHOD_POD_CLOSE'; + write; + } + + +} + +sub _printmethod { + my ($self, $methodname, $how) = @_; + return if $methodname =~ /^_/; + return if $self->meta->has_attribute($methodname); + my %internal = map {$_ => 1} qw(BUILD BUILDARGS meta can new DEMOLISHALL DESTROY + DOES isa BUILDALL does VERSION dump + ); + return if $internal{$methodname}; + my $method = $self->meta->get_method($methodname) or return; # symbols imported into namespaces i.e. not known by Moose + + return if $method->original_package_name eq __PACKAGE__; + + my $delegate_to = ''; + my $via = ''; + my $on = ''; + my $doc = ''; + my $original_pkg = $method->original_package_name; + if ($method->can('associated_attribute')) { + $delegate_to = $method->delegate_to_method; + my $aa = $method->associated_attribute; + $on = $aa->{isa}; + $via = $aa->{name}; + $original_pkg = $on; + $doc = $original_pkg->method_documentation->{$delegate_to}->{summary}; + } + else { + $doc = $method->documentation; + } + + if ($how eq 'narrow') { + $~ = 'METHOD_NARROW'; + write; + } + elsif ($how eq 'pod' and $delegate_to) { + $~ = 'METHOD_POD_DELEGATED'; + write; + } + elsif ($how eq 'pod') { + $~ = 'METHOD_POD'; + write; + } + else { + $~ = 'METHOD'; + write; + } + +# ----- format specs ----- + format METHODHEAD = + +METHODS +------- +Name delegates to on via +=========================================================================================================================================================================== +. + format METHOD = +@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<... @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<... @<<<<<<<<<<<<<<<<... +$methodname, $delegate_to, $on, $via +. + + format METHOD_NARROW = +@* +$methodname + original pkg: @* + $original_pkg + delegates to: @* + $delegate_to + on: @* + $on + via: @* + $via + +. + + format METHODHEAD_POD = + +=head1 METHODS + +. + + format METHOD_POD = + +=head2 C<@*()> + $methodname + + Defined in: @* + $original_pkg + + +. + format METHOD_POD_DELEGATED = + +=head2 C<@*()> + $methodname + + Defined in: @* + $original_pkg + Delegates to: @*() + $delegate_to + On: @* + $on + Via: @*() + $via + Doc: @* + $doc + Same as: $self->@*->@*() + $via, $delegate_to + +. + format METHOD_POD_CLOSE = + +. +# ----- / format specs ----- +} + +sub _printattrs { + my ($self, $how) = @_; + + if ($how eq 'narrow') { + print <_printattr($_, $how) for sort $self->meta->get_attribute_list; + + if ($how eq 'pod') { + $~ = 'ATTR_POD_CLOSE'; + write; + } +} + +sub _printattr { + my ($self, $attrname, $how) = @_; + return if $attrname =~ /^_/; + my $attr = $self->meta->get_attribute($attrname) or die "No attr for $attrname"; + + my $is; + $is = 'rw' if $attr->get_read_method && $attr->get_write_method; + $is = 'ro' if $attr->get_read_method && ! $attr->get_write_method; + $is = 'wo' if $attr->get_write_method && ! $attr->get_read_method; + $is = '--' if ! $attr->get_write_method && ! $attr->get_read_method; + $is or die "No \$is for $attrname"; + + my $tc = $attr->type_constraint || ''; + my $from = $attr->associated_class->name || ''; + my $reqd = $attr->is_required ? 'yes' : 'no'; + my $lazy = $attr->is_lazy ? 'yes' : 'no'; + my $has_doc = $attr->has_documentation ? 'yes' : 'no'; # *_api attributes will never have doc, but other attributes might have + my $doc = $attr->documentation || ''; + my $handles = join ', ', sort @{$attr->handles || []}; + $handles ||= ''; + + if ($how eq 'narrow') { + $~ = 'ATTR_NARROW'; + } + elsif ($how eq 'pod') { + $~ = 'ATTR_POD'; + } + else { + $~ = 'ATTR'; + } + + write; + +# ----- format specs ----- + format ATTRHEAD = + +ATTRIBUTES +---------- +Name is isa reqd lazy doc handles +============================================================================================================== +. + format ATTR = +@<<<<<<<<<<<<<<<<< @< @<<<<<<<<<<<<<<<<<<<<<<<< @<<< @<<< @<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +$attrname, $is, $tc, $reqd, $lazy, $has_doc, $handles + ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~~ + $handles +. + + format ATTR_NARROW = +@* +$attrname + is: @* + $is + isa: @* + $tc + reqd: @* + $reqd + lazy: @* + $lazy + doc: @* + $doc + handles: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + $handles + ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~~ + $handles + +. + format ATTRHEAD_POD = +=head1 ATTRIBUTES + +. + format ATTR_POD = + +=head2 C<@*> + $attrname + + is: @* + $is + isa: @* + $tc + reqd: @* + $reqd + lazy: @* + $lazy + doc: @* + $doc + handles: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + $handles + ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~~ + $handles + +. + format ATTR_POD_CLOSE = + + +. +# ----- / format specs ----- +} + + + +1; \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/perl/BaseObject.mustache b/modules/swagger-codegen/src/main/resources/perl/BaseObject.mustache index f2a58efdb68f..a41931940bae 100644 --- a/modules/swagger-codegen/src/main/resources/perl/BaseObject.mustache +++ b/modules/swagger-codegen/src/main/resources/perl/BaseObject.mustache @@ -20,8 +20,10 @@ use base ("Class::Accessor", "Class::Data::Inheritable"); #NOTE: This class is auto generated by the swagger code generator program. Do not edit the class manually. # -__PACKAGE__->mk_classdata('attribute_map'); -__PACKAGE__->mk_classdata('swagger_types'); +__PACKAGE__->mk_classdata('attribute_map' => {}); +__PACKAGE__->mk_classdata('swagger_types' => {}); +__PACKAGE__->mk_classdata('method_documentation' => {}); +__PACKAGE__->mk_classdata('class_documentation' => {}); # new object sub new { diff --git a/modules/swagger-codegen/src/main/resources/perl/Configuration.mustache b/modules/swagger-codegen/src/main/resources/perl/Configuration.mustache index d0b8b2c0e684..75a1ba7f61a6 100644 --- a/modules/swagger-codegen/src/main/resources/perl/Configuration.mustache +++ b/modules/swagger-codegen/src/main/resources/perl/Configuration.mustache @@ -10,13 +10,13 @@ use Carp; use constant VERSION => '{{moduleVersion}}'; # class/static variables -our $api_client; our $http_timeout = 180; our $http_user_agent = 'Perl-Swagger'; # authenticaiton setting our $api_key = {}; our $api_key_prefix = {}; +our $api_key_in = {}; # username and password for HTTP basic authentication our $username = ''; @@ -25,4 +25,56 @@ our $password = ''; # access token for OAuth our $access_token = ''; +sub get_tokens { + my $class = shift; + + my $tokens = {}; + $tokens->{username} = $username if $username; + $tokens->{password} = $password if $password; + $tokens->{access_token} = $access_token if $access_token; + + foreach my $token_name (keys %{ $api_key }) { + $tokens->{$token_name}->{token} = $api_key->{$token_name}; + $tokens->{$token_name}->{prefix} = $api_key_prefix->{$token_name}; + $tokens->{$token_name}->{in} = $api_key_in->{$token_name}; + } + + return $tokens; +} + +sub clear_tokens { + my $class = shift; + my %tokens = %{$class->get_tokens}; # copy + + $username = undef; + $password = undef; + $access_token = undef; + + $api_key = {}; + $api_key_prefix = {}; + $api_key_in = {}; + + return \%tokens; +} + +sub accept_tokens { + my ($class, $tokens) = @_; + + foreach my $known_name (qw(username password access_token)) { + next unless $tokens->{$known_name}; + eval "\$$known_name = delete \$tokens->{\$known_name}"; + die $@ if $@; + } + + foreach my $token_name (keys %$tokens) { + $api_key->{$token_name} = $tokens->{$token_name}->{token}; + if ($tokens->{$token_name}->{prefix}) { + $api_key_prefix->{$token_name} = $tokens->{$token_name}->{prefix}; + } + my $in = $tokens->{$token_name}->{in} || 'head'; + croak "Tokens can only go in 'head' or 'query' (not in '$in')" unless $in =~ /^(?:head|query)$/; + $api_key_in->{$token_name} = $in; + } +} + 1; diff --git a/modules/swagger-codegen/src/main/resources/perl/README.md b/modules/swagger-codegen/src/main/resources/perl/README.md new file mode 100644 index 000000000000..8d0b7695c153 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/perl/README.md @@ -0,0 +1,219 @@ +# NAME + +WWW::{{moduleName}}::Role - a Moose role for the {{appName}} + +## {{appName}} version: {{appVersion}} + +# VERSION + +Automatically generated by the Perl Swagger Codegen project: + +- Build date: {{generatedDate}} +- Build package: {{generatorClass}} +- Codegen version: + +## A note on Moose + +This role is the only component of the library that uses Moose. See +WWW::{{moduleName}}::ApiFactory for non-Moosey usage. + +# SYNOPSIS + +The Perl Swagger Codegen project builds a library of Perl modules to interact with +a web service defined by a Swagger specification. See below for how to build the +library. + +This module provides an interface to the generated library. All the classes, +objects, and methods (well, not quite \*all\*, see below) are flattened into this +role. + + package MyApp; + use Moose; + with 'WWW::{{moduleName}}::Role'; + + package main; + + my $api = MyApp->new({ tokens => $tokens }); + + my $pet = $api->get_pet_by_id(pet_id => $pet_id); + + +## Structure of the library + +The library consists of a set of API classes, one for each endpoint. These APIs +implement the method calls available on each endpoint. + +Additionally, there is a set of "object" classes, which represent the objects +returned by and sent to the methods on the endpoints. + +An API factory class is provided, which builds instances of each endpoint API. + +This Moose role flattens all the methods from the endpoint APIs onto the consuming +class. It also provides methods to retrieve the endpoint API objects, and the API +factory object, should you need it. + +For documentation of all these methods, see AUTOMATIC DOCUMENTATION below. + +## Configuring authentication + +In the normal case, the Swagger spec will describe what parameters are +required and where to put them. You just need to supply the tokens. + + my $tokens = { + # basic + username => $username, + password => $password, + + # oauth + access_token => $oauth_token, + + # keys + $some_key => { token => $token, + prefix => $prefix, + in => $in, # 'head||query', + }, + + $another => { token => $token, + prefix => $prefix, + in => $in, # 'head||query', + }, + ..., + + }; + + my $api = MyApp->new({ tokens => $tokens }); + +Note these are all optional, as are `prefix` and `in`, and depend on the API +you are accessing. Usually `prefix` and `in` will be determined by the code generator from +the spec and you will not need to set them at run time. If not, `in` will +default to 'head' and `prefix` to the empty string. + +The tokens will be placed in the `WWW::{{moduleName}}::Configuration` namespace +as follows, but you don't need to know about this. + +- `$WWW::{{moduleName}}::Configuration::username` + + String. The username for basic auth. + +- `$WWW::{{moduleName}}::Configuration::password` + + String. The password for basic auth. + +- `$WWW::{{moduleName}}::Configuration::api_key` + + Hashref. Keyed on the name of each key (there can be multiple tokens). + + $WWW::{{moduleName}}::Configuration::api_key = { + secretKey => 'aaaabbbbccccdddd', + anotherKey => '1111222233334444', + }; + +- `$WWW::{{moduleName}}::Configuration::api_key_prefix` + + Hashref. Keyed on the name of each key (there can be multiple tokens). Note not + all api keys require a prefix. + + $WWW::{{moduleName}}::Configuration::api_key_prefix = { + secretKey => 'string', + anotherKey => 'same or some other string', + }; + +- `$WWW::{{moduleName}}::Configuration::access_token` + + String. The OAuth access token. + +# METHODS + +## `base_url` + +The generated code has the `base_url` already set as a default value. This method +returns (and optionally sets, but only if the API client has not been +created yet) the current value of `base_url`. + +## `api_factory` + +Returns an API factory object. You probably won't need to call this directly. + + $self->api_factory('Pet'); # returns a WWW::{{moduleName}}::PetApi instance + + $self->pet_api; # the same + +# MISSING METHODS + +Most of the methods on the API are delegated to individual endpoint API objects +(e.g. Pet API, Store API, User API etc). Where different endpoint APIs use the +same method name (e.g. `new()`), these methods can't be delegated. So you need +to call `$api->pet_api->new()`. + +In principle, every API is susceptible to the presence of a few, random, undelegatable +method names. In practice, because of the way method names are constructed, it's +unlikely in general that any methods will be undelegatable, except for: + + new() + class_documentation() + method_documentation() + +To call these methods, you need to get a handle on the relevant object, either +by calling `$api->foo_api` or by retrieving an object, e.g. +`$api->get_pet_by_id(pet_id => $pet_id)`. They are class methods, so +you could also call them on class names. + +# BUILDING YOUR LIBRARY + +See the homepage `https://github.com/swagger-api/swagger-codegen` for full details. +But briefly, clone the git repository, build the codegen codebase, set up your build +config file, then run the API build script. You will need git, Java 7 and Apache +maven 3.0.3 or better already installed. + +The config file should specify the project name for the generated library: + + {"moduleName":"MyProjectName"} + +Your library files will be built under `WWW::MyProjectName`. + + $ git clone https://github.com/swagger-api/swagger-codegen.git + $ cd swagger-codegen + $ mvn package + $ java -jar modules/swagger-codegen-cli/target/swagger-codegen-cli.jar generate \ + -i [URL or file path to JSON swagger API spec] \ + -l perl \ + -c /path/to/config/file.json \ + -o /path/to/output/folder + +Bang, all done. Run the `autodoc` script in the `bin` directory to see the API +you just built. + +# AUTOMATIC DOCUMENTATION + +You can print out a summary of the generated API by running the included +`autodoc` script in the `bin` directory of your generated library. A few +output formats are supported: + + Usage: autodoc [OPTION] + + -w wide format (default) + -n narrow format + -p POD format + -H HTML format + -m Markdown format + -h print this help message + -c your application class + + +The `-c` option allows you to load and inspect your own application. A dummy +namespace is used if you don't supply your own class. + +# DOCUMENTATION FROM THE SWAGGER SPEC + +Additional documentation for each class and method may be provided by the Swagger +spec. If so, this is available via the `class_documentation()` and +`method_documentation()` methods on each generated object class, and the +`method_documentation()` method on the endpoint API classes: + + my $cmdoc = $api->pet_api->method_documentation->{$method_name}; + + my $odoc = $api->get_pet_by_id->(pet_id => $pet_id)->class_documentation; + my $omdoc = $api->get_pet_by_id->(pet_id => $pet_id)->method_documentation->{method_name}; + + +Each of these calls returns a hashref with various useful pieces of information. diff --git a/modules/swagger-codegen/src/main/resources/perl/Role.mustache b/modules/swagger-codegen/src/main/resources/perl/Role.mustache new file mode 100644 index 000000000000..7bca8cca78d7 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/perl/Role.mustache @@ -0,0 +1,323 @@ +package WWW::{{moduleName}}::Role; +use utf8; + +use Moose::Role; +use namespace::autoclean; +use Class::Inspector; +use Log::Any qw($log); +use WWW::{{moduleName}}::ApiFactory; + +has base_url => ( is => 'ro', + required => 0, + isa => 'Str', + documentation => 'Root of the server that requests are sent to', + ); + +has api_factory => ( is => 'ro', + isa => 'WWW::{{moduleName}}::ApiFactory', + builder => '_build_af', + lazy => 1, + documentation => 'Builds an instance of the endpoint API class', + ); + +has tokens => ( is => 'ro', + isa => 'HashRef', + required => 0, + default => sub { {} }, + documentation => 'The auth tokens required by the application - basic, OAuth and/or API key(s)', + ); + +has _cfg => ( is => 'ro', + isa => 'Str', + default => 'WWW::{{moduleName}}::Configuration', + ); + +has version_info => ( is => 'ro', + isa => 'HashRef', + default => sub { { + app_name => '{{appName}}', + app_version => '{{appVersion}}', + generated_date => '{{generatedDate}}', + generator_class => '{{generatorClass}}', + } }, + documentation => 'Information about the application version and the codegen codebase version' + ); + +sub BUILD { + my $self = shift; + + $self->_cfg->accept_tokens( $self->tokens ) if keys %{$self->tokens}; + + # ignore these symbols imported into API namespaces + my %outsiders = map {$_ => 1} qw( croak ); + + my %delegates; + + # collect the methods callable on each API + foreach my $api_name ($self->api_factory->apis_available) { + my $api_class = $self->api_factory->classname_for($api_name); + my $methods = Class::Inspector->methods($api_class, 'expanded'); # not Moose, so use CI instead + my @local_methods = grep {! /^_/} grep {! $outsiders{$_}} map {$_->[2]} grep {$_->[1] eq $api_class} @$methods; + push( @{$delegates{$_}}, {api_name => $api_name, api_class => $api_class} ) for @local_methods; + } + + # remove clashes + foreach my $method (keys %delegates) { + if ( @{$delegates{$method}} > 1 ) { + my ($apis) = delete $delegates{$method}; + } + } + + # build the flattened API + foreach my $api_name ($self->api_factory->apis_available) { + my $att_name = sprintf "%s_api", lc($api_name); + my $api_class = $self->api_factory->classname_for($api_name); + my @delegated = grep { $delegates{$_}->[0]->{api_name} eq $api_name } keys %delegates; + $log->debugf("Adding API: '%s' handles %s", $att_name, join ', ', @delegated); + $self->meta->add_attribute( $att_name => ( + is => 'ro', + isa => $api_class, + default => sub {$self->api_factory->get_api($api_name)}, + lazy => 1, + handles => \@delegated, + ) ); + } +} + +sub _build_af { + my $self = shift; + my %args; + $args{base_url} = $self->base_url if $self->base_url; + return WWW::{{moduleName}}::ApiFactory->new(%args); +} + +=head1 NAME + +WWW::{{moduleName}}::Role - a Moose role for the {{appName}} + +=head2 {{appName}} version: {{appVersion}} + +=head1 VERSION + +Automatically generated by the Perl Swagger Codegen project: + +=over 4 + +=item Build date: {{generatedDate}} + +=item Build package: {{generatorClass}} + +=item Codegen version: + +=back + +=head2 A note on Moose + +This role is the only component of the library that uses Moose. See +WWW::{{moduleName}}::ApiFactory for non-Moosey usage. + +=head1 SYNOPSIS + +The Perl Swagger Codegen project builds a library of Perl modules to interact with +a web service defined by a Swagger specification. See below for how to build the +library. + +This module provides an interface to the generated library. All the classes, +objects, and methods (well, not quite *all*, see below) are flattened into this +role. + + package MyApp; + use Moose; + with 'WWW::{{moduleName}}::Role'; + + package main; + + my $api = MyApp->new({ tokens => $tokens }); + + my $pet = $api->get_pet_by_id(pet_id => $pet_id); + +=head2 Structure of the library + +The library consists of a set of API classes, one for each endpoint. These APIs +implement the method calls available on each endpoint. + +Additionally, there is a set of "object" classes, which represent the objects +returned by and sent to the methods on the endpoints. + +An API factory class is provided, which builds instances of each endpoint API. + +This Moose role flattens all the methods from the endpoint APIs onto the consuming +class. It also provides methods to retrieve the endpoint API objects, and the API +factory object, should you need it. + +For documentation of all these methods, see AUTOMATIC DOCUMENTATION below. + +=head2 Configuring authentication + +In the normal case, the Swagger spec will describe what parameters are +required and where to put them. You just need to supply the tokens. + + my $tokens = { + # basic + username => $username, + password => $password, + + # oauth + access_token => $oauth_token, + + # keys + $some_key => { token => $token, + prefix => $prefix, + in => $in, # 'head||query', + }, + + $another => { token => $token, + prefix => $prefix, + in => $in, # 'head||query', + }, + ..., + + }; + + my $api = MyApp->new({ tokens => $tokens }); + +Note these are all optional, as are C and C, and depend on the API +you are accessing. Usually C and C will be determined by the code generator from +the spec and you will not need to set them at run time. If not, C will +default to 'head' and C to the empty string. + +The tokens will be placed in the C namespace +as follows, but you don't need to know about this. + +=over 4 + +=item C<$WWW::{{moduleName}}::Configuration::username> + +String. The username for basic auth. + +=item C<$WWW::{{moduleName}}::Configuration::password> + +String. The password for basic auth. + +=item C<$WWW::{{moduleName}}::Configuration::api_key> + +Hashref. Keyed on the name of each key (there can be multiple tokens). + + $WWW::{{moduleName}}::Configuration::api_key = { + secretKey => 'aaaabbbbccccdddd', + anotherKey => '1111222233334444', + }; + +=item C<$WWW::{{moduleName}}::Configuration::api_key_prefix> + +Hashref. Keyed on the name of each key (there can be multiple tokens). Note not +all api keys require a prefix. + + $WWW::{{moduleName}}::Configuration::api_key_prefix = { + secretKey => 'string', + anotherKey => 'same or some other string', + }; + +=item C<$WWW::{{moduleName}}::Configuration::access_token> + +String. The OAuth access token. + +=back + +=head1 METHODS + +=head2 C + +The generated code has the C already set as a default value. This method +returns (and optionally sets, but only if the API client has not been +created yet) the current value of C. + +=head2 C + +Returns an API factory object. You probably won't need to call this directly. + + $self->api_factory('Pet'); # returns a WWW::{{moduleName}}::PetApi instance + + $self->pet_api; # the same + +=head1 MISSING METHODS + +Most of the methods on the API are delegated to individual endpoint API objects +(e.g. Pet API, Store API, User API etc). Where different endpoint APIs use the +same method name (e.g. C), these methods can't be delegated. So you need +to call C<$api-Epet_api-Enew()>. + +In principle, every API is susceptible to the presence of a few, random, undelegatable +method names. In practice, because of the way method names are constructed, it's +unlikely in general that any methods will be undelegatable, except for: + + new() + class_documentation() + method_documentation() + +To call these methods, you need to get a handle on the relevant object, either +by calling C<$api-Efoo_api> or by retrieving an object, e.g. +C<$api-Eget_pet_by_id(pet_id =E $pet_id)>. They are class methods, so +you could also call them on class names. + +=head1 BUILDING YOUR LIBRARY + +See the homepage C for full details. +But briefly, clone the git repository, build the codegen codebase, set up your build +config file, then run the API build script. You will need git, Java 7 and Apache +maven 3.0.3 or better already installed. + +The config file should specify the project name for the generated library: + + {"moduleName":"MyProjectName"} + +Your library files will be built under C. + + $ git clone https://github.com/swagger-api/swagger-codegen.git + $ cd swagger-codegen + $ mvn package + $ java -jar modules/swagger-codegen-cli/target/swagger-codegen-cli.jar generate \ + -i [URL or file path to JSON swagger API spec] \ + -l perl \ + -c /path/to/config/file.json \ + -o /path/to/output/folder + +Bang, all done. Run the C script in the C directory to see the API +you just built. + +=head1 AUTOMATIC DOCUMENTATION + +You can print out a summary of the generated API by running the included +C script in the C directory of your generated library. A few +output formats are supported: + + Usage: autodoc [OPTION] + + -w wide format (default) + -n narrow format + -p POD format + -H HTML format + -m Markdown format + -h print this help message + -c your application class + +The C<-c> option allows you to load and inspect your own application. A dummy +namespace is used if you don't supply your own class. + +=head1 DOCUMENTATION FROM THE SWAGGER SPEC + +Additional documentation for each class and method may be provided by the Swagger +spec. If so, this is available via the C and +C methods on each generated object class, and the +C method on the endpoint API classes: + + my $cmdoc = $api->pet_api->method_documentation->{$method_name}; + + my $odoc = $api->get_pet_by_id->(pet_id => $pet_id)->class_documentation; + my $omdoc = $api->get_pet_by_id->(pet_id => $pet_id)->method_documentation->{method_name}; + +Each of these calls returns a hashref with various useful pieces of information. + +=cut + +1; diff --git a/modules/swagger-codegen/src/main/resources/perl/api.mustache b/modules/swagger-codegen/src/main/resources/perl/api.mustache index d305d69b7faa..f25c63a528cc 100644 --- a/modules/swagger-codegen/src/main/resources/perl/api.mustache +++ b/modules/swagger-codegen/src/main/resources/perl/api.mustache @@ -30,11 +30,14 @@ use Log::Any qw($log); use WWW::{{moduleName}}::ApiClient; use WWW::{{moduleName}}::Configuration; +use base "Class::Data::Inheritable"; + +__PACKAGE__->mk_classdata('method_documentation' => {}); + sub new { my $class = shift; - my $default_api_client = $WWW::{{moduleName}}::Configuration::api_client ? $WWW::{{moduleName}}::Configuration::api_client : WWW::{{moduleName}}::ApiClient->new; my (%self) = ( - 'api_client' => $default_api_client, + 'api_client' => WWW::{{moduleName}}::ApiClient->instance, @_ ); @@ -49,13 +52,31 @@ sub new { {{#operations}} {{#operation}} + # # {{{nickname}}} # # {{{summary}}} # {{#allParams}}# @param {{dataType}} ${{paramName}} {{description}} {{#required}}(required){{/required}}{{^required}}(optional){{/required}} -{{/allParams}}# @return {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} +{{/allParams}} +{ + my $params = { +{{#allParams}} + '{{paramName}}' => { + data_type => '{{dataType}}', + description => '{{description}}', + required => {{#required}}'1'{{/required}}{{^required}}'0'{{/required}}, + }, +{{/allParams}} + }; + __PACKAGE__->method_documentation->{ {{nickname}} } = { + summary => '{{summary}}', + params => $params, + returns => {{#returnType}}'{{{returnType}}}'{{/returnType}}{{^returnType}}undef{{/returnType}}, + }; +} +# @return {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} # sub {{nickname}} { my ($self, %args) = @_; @@ -112,7 +133,7 @@ sub {{nickname}} { }{{/bodyParams}} # authentication setting, if any - my $auth_settings = [{{#authMethods}}'{{name}}'{{#hasMore}}, {{/hasMore}}{{/authMethods}}]; + my $auth_settings = [qw({{#authMethods}}{{name}} {{/authMethods}})]; # make the API Call {{#returnType}}my $response = $self->{api_client}->call_api($_resource_path, $_method, diff --git a/modules/swagger-codegen/src/main/resources/perl/autodoc.script.mustache b/modules/swagger-codegen/src/main/resources/perl/autodoc.script.mustache new file mode 100644 index 000000000000..240936d9b510 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/perl/autodoc.script.mustache @@ -0,0 +1,77 @@ +#!/usr/bin/perl +use FindBin; +use File::Spec; +use lib File::Spec->catdir($FindBin::Bin, '..', 'lib'); + +use Moose::Util qw(apply_all_roles); +use Getopt::Std; + +my %options=(); +getopts("wnphmHc:", \%options); +help if $options{h}; + +my $my_app = $options{c} || 'My::App'; + +if ($options{c}) { + eval <new; + +if ($options{H}) { + my $pod2html = "pod2html --backlink --css http://st.pimg.net/tucs/style.css?3"; + open STDOUT, "| $pod2html" or die "Can't fork: $!"; + $api->autodoc($opt); + close STDOUT or die "Can't close: $!"; +} +elsif ($options{m}) { + my $pod2markdown = "pod2markdown --html-encode-chars 1"; + open STDOUT, "| $pod2markdown" or die "Can't fork: $!"; + $api->autodoc($opt); + close STDOUT or die "Can't close: $!"; +} +else { + $api->autodoc($opt); +} + +exit(0); + +# -------------------- +sub help { + print <class_documentation({description => '{{description}}', + class => '{{classname}}', + required => [], # TODO +} ); + +__PACKAGE__->method_documentation({ + {{#vars}}'{{name}}' => { + datatype => '{{datatype}}', + base_name => '{{baseName}}', + description => '{{description}}', + format => '{{format}}', + read_only => '{{readOnly}}', + }, + {{/vars}} +}); + __PACKAGE__->swagger_types( { {{#vars}}'{{name}}' => '{{{datatype}}}'{{#hasMore}}, {{/hasMore}}{{/vars}} diff --git a/samples/client/petstore/perl/README.md b/samples/client/petstore/perl/README.md new file mode 100644 index 000000000000..adfe2455d658 --- /dev/null +++ b/samples/client/petstore/perl/README.md @@ -0,0 +1,281 @@ +# NAME + +My::App + +# VERSION + +## Swagger Petstore version: 1.0.0 + +Automatically generated by the Perl Swagger Codegen project: + +- Build date: 2015-11-13T20:46:43.271Z +- Build package: class io.swagger.codegen.languages.PerlClientCodegen +- Codegen version: + +# INHERITANCE + +## Base class(es) + +Moose::Object + +## Direct subclasses + +## All subclasses + +# COMPOSITION + +My::App composes the following roles: + +## `WWW::SwaggerClient::Role` + +Requires: + +# METHODS + +## `add_pet()` + + Defined in: WWW::SwaggerClient::PetApi + Delegates to: add_pet() + On: WWW::SwaggerClient::PetApi + Via: pet_api() + Doc: Add a new pet to the store + Same as: $self->pet_api->add_pet() + +## `create_user()` + + Defined in: WWW::SwaggerClient::UserApi + Delegates to: create_user() + On: WWW::SwaggerClient::UserApi + Via: user_api() + Doc: Create user + Same as: $self->user_api->create_user() + +## `create_users_with_array_input()` + + Defined in: WWW::SwaggerClient::UserApi + Delegates to: create_users_with_array_input() + On: WWW::SwaggerClient::UserApi + Via: user_api() + Doc: Creates list of users with given input array + Same as: $self->user_api->create_users_with_array_input() + +## `create_users_with_list_input()` + + Defined in: WWW::SwaggerClient::UserApi + Delegates to: create_users_with_list_input() + On: WWW::SwaggerClient::UserApi + Via: user_api() + Doc: Creates list of users with given input array + Same as: $self->user_api->create_users_with_list_input() + +## `delete_order()` + + Defined in: WWW::SwaggerClient::StoreApi + Delegates to: delete_order() + On: WWW::SwaggerClient::StoreApi + Via: store_api() + Doc: Delete purchase order by ID + Same as: $self->store_api->delete_order() + +## `delete_pet()` + + Defined in: WWW::SwaggerClient::PetApi + Delegates to: delete_pet() + On: WWW::SwaggerClient::PetApi + Via: pet_api() + Doc: Deletes a pet + Same as: $self->pet_api->delete_pet() + +## `delete_user()` + + Defined in: WWW::SwaggerClient::UserApi + Delegates to: delete_user() + On: WWW::SwaggerClient::UserApi + Via: user_api() + Doc: Delete user + Same as: $self->user_api->delete_user() + +## `find_pets_by_status()` + + Defined in: WWW::SwaggerClient::PetApi + Delegates to: find_pets_by_status() + On: WWW::SwaggerClient::PetApi + Via: pet_api() + Doc: Finds Pets by status + Same as: $self->pet_api->find_pets_by_status() + +## `find_pets_by_tags()` + + Defined in: WWW::SwaggerClient::PetApi + Delegates to: find_pets_by_tags() + On: WWW::SwaggerClient::PetApi + Via: pet_api() + Doc: Finds Pets by tags + Same as: $self->pet_api->find_pets_by_tags() + +## `get_inventory()` + + Defined in: WWW::SwaggerClient::StoreApi + Delegates to: get_inventory() + On: WWW::SwaggerClient::StoreApi + Via: store_api() + Doc: Returns pet inventories by status + Same as: $self->store_api->get_inventory() + +## `get_order_by_id()` + + Defined in: WWW::SwaggerClient::StoreApi + Delegates to: get_order_by_id() + On: WWW::SwaggerClient::StoreApi + Via: store_api() + Doc: Find purchase order by ID + Same as: $self->store_api->get_order_by_id() + +## `get_pet_by_id()` + + Defined in: WWW::SwaggerClient::PetApi + Delegates to: get_pet_by_id() + On: WWW::SwaggerClient::PetApi + Via: pet_api() + Doc: Find pet by ID + Same as: $self->pet_api->get_pet_by_id() + +## `get_user_by_name()` + + Defined in: WWW::SwaggerClient::UserApi + Delegates to: get_user_by_name() + On: WWW::SwaggerClient::UserApi + Via: user_api() + Doc: Get user by user name + Same as: $self->user_api->get_user_by_name() + +## `login_user()` + + Defined in: WWW::SwaggerClient::UserApi + Delegates to: login_user() + On: WWW::SwaggerClient::UserApi + Via: user_api() + Doc: Logs user into the system + Same as: $self->user_api->login_user() + +## `logout_user()` + + Defined in: WWW::SwaggerClient::UserApi + Delegates to: logout_user() + On: WWW::SwaggerClient::UserApi + Via: user_api() + Doc: Logs out current logged in user session + Same as: $self->user_api->logout_user() + +## `place_order()` + + Defined in: WWW::SwaggerClient::StoreApi + Delegates to: place_order() + On: WWW::SwaggerClient::StoreApi + Via: store_api() + Doc: Place an order for a pet + Same as: $self->store_api->place_order() + +## `update_pet()` + + Defined in: WWW::SwaggerClient::PetApi + Delegates to: update_pet() + On: WWW::SwaggerClient::PetApi + Via: pet_api() + Doc: Update an existing pet + Same as: $self->pet_api->update_pet() + +## `update_pet_with_form()` + + Defined in: WWW::SwaggerClient::PetApi + Delegates to: update_pet_with_form() + On: WWW::SwaggerClient::PetApi + Via: pet_api() + Doc: Updates a pet in the store with form data + Same as: $self->pet_api->update_pet_with_form() + +## `update_user()` + + Defined in: WWW::SwaggerClient::UserApi + Delegates to: update_user() + On: WWW::SwaggerClient::UserApi + Via: user_api() + Doc: Updated user + Same as: $self->user_api->update_user() + +## `upload_file()` + + Defined in: WWW::SwaggerClient::PetApi + Delegates to: upload_file() + On: WWW::SwaggerClient::PetApi + Via: pet_api() + Doc: uploads an image + Same as: $self->pet_api->upload_file() + +# ATTRIBUTES + +## `api_factory` + + is: ro + isa: WWW::SwaggerClient::ApiFactory + reqd: no + lazy: yes + doc: Builds an instance of the endpoint API class + handles: + +## `base_url` + + is: ro + isa: Str + reqd: no + lazy: no + doc: Root of the server that requests are sent to + handles: + +## `pet_api` + + is: ro + isa: WWW::SwaggerClient::PetApi + reqd: no + lazy: yes + doc: + handles: add_pet, delete_pet, find_pets_by_status, find_pets_by_tags, + get_pet_by_id, update_pet, update_pet_with_form, upload_file + +## `store_api` + + is: ro + isa: WWW::SwaggerClient::StoreApi + reqd: no + lazy: yes + doc: + handles: delete_order, get_inventory, get_order_by_id, place_order + +## `tokens` + + is: ro + isa: HashRef + reqd: no + lazy: no + doc: The auth tokens required by the application - basic, OAuth and/or API key(s) + handles: + +## `user_api` + + is: ro + isa: WWW::SwaggerClient::UserApi + reqd: no + lazy: yes + doc: + handles: create_user, create_users_with_array_input, + create_users_with_list_input, delete_user, get_user_by_name, + login_user, logout_user, update_user + +## `version_info` + + is: ro + isa: HashRef + reqd: no + lazy: no + doc: Information about the application version and the codegen codebase version + handles: diff --git a/samples/client/petstore/perl/bin/autodoc b/samples/client/petstore/perl/bin/autodoc new file mode 100644 index 000000000000..049fcf7fecf2 --- /dev/null +++ b/samples/client/petstore/perl/bin/autodoc @@ -0,0 +1,77 @@ +#!/usr/bin/perl +use FindBin; +use File::Spec; +use lib File::Spec->catdir($FindBin::Bin, '..', 'lib'); + +use Moose::Util qw(apply_all_roles); +use Getopt::Std; + +my %options=(); +getopts("wnphmHc:", \%options); +help if $options{h}; + +my $my_app = $options{c} || 'My::App'; + +if ($options{c}) { + eval <new; + +if ($options{H}) { + my $pod2html = "pod2html --backlink --css http://st.pimg.net/tucs/style.css?3"; + open STDOUT, "| $pod2html" or die "Can't fork: $!"; + $api->autodoc($opt); + close STDOUT or die "Can't close: $!"; +} +elsif ($options{m}) { + my $pod2markdown = "pod2markdown --html-encode-chars 1"; + open STDOUT, "| $pod2markdown" or die "Can't fork: $!"; + $api->autodoc($opt); + close STDOUT or die "Can't close: $!"; +} +else { + $api->autodoc($opt); +} + +exit(0); + +# -------------------- +sub help { + print <{$api_key}) { - return $WWW::SwaggerClient::Configuration::api_key_prefix->{$api_key}." ".$WWW::SwaggerClient::Configuration::api_key->{$api_key}; - } else { - return $WWW::SwaggerClient::Configuration::api_key->{$api_key}; - } -} + my ($self, $key_name) = @_; + + my $api_key = $WWW::SwaggerClient::Configuration::api_key->{$key_name}; + + return unless $api_key; + + my $prefix = $WWW::SwaggerClient::Configuration::api_key_prefix->{$key_name}; + return $prefix ? "$prefix $api_key" : $api_key; +} # update header and query param based on authentication setting # @@ -304,17 +310,8 @@ sub get_api_key_with_prefix sub update_params_for_auth { my ($self, $header_params, $query_params, $auth_settings) = @_; - # we can defer to the application - if ($self->{auth_setup_handler} && ref($self->{auth_setup_handler}) eq 'CODE') { - $self->{auth_setup_handler}->( api_client => $self, - header_params => $header_params, - query_params => $query_params, - auth_settings => $auth_settings, # presumably this won't be defined if we're doing it this way - ); - return; - } - - return if (!defined($auth_settings) || scalar(@$auth_settings) == 0); + return $self->_global_auth_setup($header_params, $query_params) + unless $auth_settings && @$auth_settings; # one endpoint can have more than 1 auth settings foreach my $auth (@$auth_settings) { @@ -331,10 +328,47 @@ sub update_params_for_auth { } else { - # TODO show warning about security definition not found + # TODO show warning about security definition not found } } } +# The endpoint API class has not found any settings for auth. This may be deliberate, +# in which case update_params_for_auth() will be a no-op. But it may also be that the +# swagger spec does not describe the intended authorization. So we check in the config for any +# auth tokens and if we find any, we use them for all endpoints; +sub _global_auth_setup { + my ($self, $header_params, $query_params) = @_; + + my $tokens = $self->_cfg->get_tokens; + return unless keys %$tokens; + + # basic + if (my $uname = delete $tokens->{username}) { + my $pword = delete $tokens->{password}; + $header_params->{'Authorization'} = 'Basic '.encode_base64($uname.":".$pword); + } + + # oauth + if (my $access_token = delete $tokens->{access_token}) { + $header_params->{'Authorization'} = 'Bearer ' . $access_token; + } + + # other keys + foreach my $token_name (keys %$tokens) { + my $in = $tokens->{$token_name}->{in}; + my $token = $self->get_api_key_with_prefix($token_name); + if ($in eq 'head') { + $header_params->{$token_name} = $token; + } + elsif ($in eq 'query') { + $query_params->{$token_name} = $token; + } + else { + die "Don't know where to put token '$token_name' ('$in' is not 'head' or 'query')"; + } + } +} + 1; diff --git a/samples/client/petstore/perl/lib/WWW/SwaggerClient/ApiFactory.pm b/samples/client/petstore/perl/lib/WWW/SwaggerClient/ApiFactory.pm index 701a22603c53..f0846a9b5944 100644 --- a/samples/client/petstore/perl/lib/WWW/SwaggerClient/ApiFactory.pm +++ b/samples/client/petstore/perl/lib/WWW/SwaggerClient/ApiFactory.pm @@ -21,9 +21,7 @@ use WWW::SwaggerClient::ApiClient; use WWW::SwaggerClient::ApiFactory; - my $api_factory = WWW::SwaggerClient::ApiFactory->new( base_url => 'http://petstore.swagger.io/v2', - ..., # other args for ApiClient constructor - ); + my $api_factory = WWW::SwaggerClient::ApiFactory->new( ... ); # any args for ApiClient constructor # later... my $pet_api = $api_factory->get_api('Pet'); @@ -47,26 +45,16 @@ my %_apis = map { $_ =~ /^WWW::SwaggerClient::(.*)$/; $1 => $_ } =head1 new() - All parameters are optional, and are passed to and stored on the api_client object. + Any parameters are optional, and are passed to and stored on the api_client object. - base_url: supply this to change the default base URL taken from the Swagger definition. + base_url: (optional) + supply this to change the default base URL taken from the Swagger definition. - auth_setup_handler: a coderef you can supply to set up authentication. - - The coderef receives a hashref with keys: api_client, query_params, header_params, auth_settings. - - my $api_factory = WWW::SwaggerClient::ApiFactory->new( auth_setup_handler => \&setup_auth ); ); - - sub setup_auth { - my %p = @_; - $p{header_params}->{'X-SomeApp-FunkyKeyName'} = 'aaaaabbbbbcccccddddd'; - } - =cut sub new { my ($class, %p) = (shift, @_); - $p{api_client} = WWW::SwaggerClient::ApiClient->new(%p); + $p{api_client} = WWW::SwaggerClient::ApiClient->instance(%p); return bless \%p, $class; } @@ -95,4 +83,18 @@ sub get_api { sub api_client { $_[0]->{api_client} } +=head1 apis_available() +=cut + +sub apis_available { return map { $_ =~ s/Api$//; $_ } sort keys %_apis } + +=head1 classname_for() +=cut + +sub classname_for { + my ($self, $api_name) = @_; + return $_apis{"${api_name}Api"}; +} + + 1; diff --git a/samples/client/petstore/perl/lib/WWW/SwaggerClient/Configuration.pm b/samples/client/petstore/perl/lib/WWW/SwaggerClient/Configuration.pm index 6a4afe254e0b..150db4cfac2e 100644 --- a/samples/client/petstore/perl/lib/WWW/SwaggerClient/Configuration.pm +++ b/samples/client/petstore/perl/lib/WWW/SwaggerClient/Configuration.pm @@ -10,13 +10,13 @@ use Carp; use constant VERSION => '1.0.0'; # class/static variables -our $api_client; our $http_timeout = 180; our $http_user_agent = 'Perl-Swagger'; # authenticaiton setting our $api_key = {}; our $api_key_prefix = {}; +our $api_key_in = {}; # username and password for HTTP basic authentication our $username = ''; @@ -25,4 +25,56 @@ our $password = ''; # access token for OAuth our $access_token = ''; +sub get_tokens { + my $class = shift; + + my $tokens = {}; + $tokens->{username} = $username if $username; + $tokens->{password} = $password if $password; + $tokens->{access_token} = $access_token if $access_token; + + foreach my $token_name (keys %{ $api_key }) { + $tokens->{$token_name}->{token} = $api_key->{$token_name}; + $tokens->{$token_name}->{prefix} = $api_key_prefix->{$token_name}; + $tokens->{$token_name}->{in} = $api_key_in->{$token_name}; + } + + return $tokens; +} + +sub clear_tokens { + my $class = shift; + my %tokens = %{$class->get_tokens}; # copy + + $username = undef; + $password = undef; + $access_token = undef; + + $api_key = {}; + $api_key_prefix = {}; + $api_key_in = {}; + + return \%tokens; +} + +sub accept_tokens { + my ($class, $tokens) = @_; + + foreach my $known_name (qw(username password access_token)) { + next unless $tokens->{$known_name}; + eval "\$$known_name = delete \$tokens->{\$known_name}"; + die $@ if $@; + } + + foreach my $token_name (keys %$tokens) { + $api_key->{$token_name} = $tokens->{$token_name}->{token}; + if ($tokens->{$token_name}->{prefix}) { + $api_key_prefix->{$token_name} = $tokens->{$token_name}->{prefix}; + } + my $in = $tokens->{$token_name}->{in} || 'head'; + croak "Tokens can only go in 'head' or 'query' (not in '$in')" unless $in =~ /^(?:head|query)$/; + $api_key_in->{$token_name} = $in; + } +} + 1; diff --git a/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/BaseObject.pm b/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/BaseObject.pm index fee2b06fb0ee..f99b7715ae8d 100644 --- a/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/BaseObject.pm +++ b/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/BaseObject.pm @@ -20,8 +20,10 @@ use base ("Class::Accessor", "Class::Data::Inheritable"); #NOTE: This class is auto generated by the swagger code generator program. Do not edit the class manually. # -__PACKAGE__->mk_classdata('attribute_map'); -__PACKAGE__->mk_classdata('swagger_types'); +__PACKAGE__->mk_classdata('attribute_map' => {}); +__PACKAGE__->mk_classdata('swagger_types' => {}); +__PACKAGE__->mk_classdata('method_documentation' => {}); +__PACKAGE__->mk_classdata('class_documentation' => {}); # new object sub new { diff --git a/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/Category.pm b/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/Category.pm index 1e0629250377..43c12b040c73 100644 --- a/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/Category.pm +++ b/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/Category.pm @@ -19,6 +19,29 @@ use base "WWW::SwaggerClient::Object::BaseObject"; #NOTE: This class is auto generated by the swagger code generator program. Do not edit the class manually. # +__PACKAGE__->class_documentation({description => '', + class => 'Category', + required => [], # TODO +} ); + +__PACKAGE__->method_documentation({ + 'id' => { + datatype => 'int', + base_name => 'id', + description => '', + format => '', + read_only => '', + }, + 'name' => { + datatype => 'string', + base_name => 'name', + description => '', + format => '', + read_only => '', + }, + +}); + __PACKAGE__->swagger_types( { 'id' => 'int', 'name' => 'string' diff --git a/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/Order.pm b/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/Order.pm index 70b3db2cfc00..ea5f6160ee5f 100644 --- a/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/Order.pm +++ b/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/Order.pm @@ -19,6 +19,57 @@ use base "WWW::SwaggerClient::Object::BaseObject"; #NOTE: This class is auto generated by the swagger code generator program. Do not edit the class manually. # +__PACKAGE__->class_documentation({description => '', + class => 'Order', + required => [], # TODO +} ); + +__PACKAGE__->method_documentation({ + 'id' => { + datatype => 'int', + base_name => 'id', + description => '', + format => '', + read_only => '', + }, + 'pet_id' => { + datatype => 'int', + base_name => 'petId', + description => '', + format => '', + read_only => '', + }, + 'quantity' => { + datatype => 'int', + base_name => 'quantity', + description => '', + format => '', + read_only => '', + }, + 'ship_date' => { + datatype => 'DateTime', + base_name => 'shipDate', + description => '', + format => '', + read_only => '', + }, + 'status' => { + datatype => 'string', + base_name => 'status', + description => 'Order Status', + format => '', + read_only => '', + }, + 'complete' => { + datatype => 'boolean', + base_name => 'complete', + description => '', + format => '', + read_only => '', + }, + +}); + __PACKAGE__->swagger_types( { 'id' => 'int', 'pet_id' => 'int', diff --git a/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/Pet.pm b/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/Pet.pm index 3ff3f50b3999..a1aeb1341784 100644 --- a/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/Pet.pm +++ b/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/Pet.pm @@ -19,6 +19,57 @@ use base "WWW::SwaggerClient::Object::BaseObject"; #NOTE: This class is auto generated by the swagger code generator program. Do not edit the class manually. # +__PACKAGE__->class_documentation({description => '', + class => 'Pet', + required => [], # TODO +} ); + +__PACKAGE__->method_documentation({ + 'id' => { + datatype => 'int', + base_name => 'id', + description => '', + format => '', + read_only => '', + }, + 'category' => { + datatype => 'Category', + base_name => 'category', + description => '', + format => '', + read_only => '', + }, + 'name' => { + datatype => 'string', + base_name => 'name', + description => '', + format => '', + read_only => '', + }, + 'photo_urls' => { + datatype => 'ARRAY[string]', + base_name => 'photoUrls', + description => '', + format => '', + read_only => '', + }, + 'tags' => { + datatype => 'ARRAY[Tag]', + base_name => 'tags', + description => '', + format => '', + read_only => '', + }, + 'status' => { + datatype => 'string', + base_name => 'status', + description => 'pet status in the store', + format => '', + read_only => '', + }, + +}); + __PACKAGE__->swagger_types( { 'id' => 'int', 'category' => 'Category', diff --git a/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/Tag.pm b/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/Tag.pm index bf97f210a379..a50eded7cde0 100644 --- a/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/Tag.pm +++ b/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/Tag.pm @@ -19,6 +19,29 @@ use base "WWW::SwaggerClient::Object::BaseObject"; #NOTE: This class is auto generated by the swagger code generator program. Do not edit the class manually. # +__PACKAGE__->class_documentation({description => '', + class => 'Tag', + required => [], # TODO +} ); + +__PACKAGE__->method_documentation({ + 'id' => { + datatype => 'int', + base_name => 'id', + description => '', + format => '', + read_only => '', + }, + 'name' => { + datatype => 'string', + base_name => 'name', + description => '', + format => '', + read_only => '', + }, + +}); + __PACKAGE__->swagger_types( { 'id' => 'int', 'name' => 'string' diff --git a/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/User.pm b/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/User.pm index 36fc7baf6ee5..cb431b1e059f 100644 --- a/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/User.pm +++ b/samples/client/petstore/perl/lib/WWW/SwaggerClient/Object/User.pm @@ -19,6 +19,71 @@ use base "WWW::SwaggerClient::Object::BaseObject"; #NOTE: This class is auto generated by the swagger code generator program. Do not edit the class manually. # +__PACKAGE__->class_documentation({description => '', + class => 'User', + required => [], # TODO +} ); + +__PACKAGE__->method_documentation({ + 'id' => { + datatype => 'int', + base_name => 'id', + description => '', + format => '', + read_only => '', + }, + 'username' => { + datatype => 'string', + base_name => 'username', + description => '', + format => '', + read_only => '', + }, + 'first_name' => { + datatype => 'string', + base_name => 'firstName', + description => '', + format => '', + read_only => '', + }, + 'last_name' => { + datatype => 'string', + base_name => 'lastName', + description => '', + format => '', + read_only => '', + }, + 'email' => { + datatype => 'string', + base_name => 'email', + description => '', + format => '', + read_only => '', + }, + 'password' => { + datatype => 'string', + base_name => 'password', + description => '', + format => '', + read_only => '', + }, + 'phone' => { + datatype => 'string', + base_name => 'phone', + description => '', + format => '', + read_only => '', + }, + 'user_status' => { + datatype => 'int', + base_name => 'userStatus', + description => 'User Status', + format => '', + read_only => '', + }, + +}); + __PACKAGE__->swagger_types( { 'id' => 'int', 'username' => 'string', diff --git a/samples/client/petstore/perl/lib/WWW/SwaggerClient/PetApi.pm b/samples/client/petstore/perl/lib/WWW/SwaggerClient/PetApi.pm index 26b9f42e620e..06ccfca98e80 100644 --- a/samples/client/petstore/perl/lib/WWW/SwaggerClient/PetApi.pm +++ b/samples/client/petstore/perl/lib/WWW/SwaggerClient/PetApi.pm @@ -30,11 +30,14 @@ use Log::Any qw($log); use WWW::SwaggerClient::ApiClient; use WWW::SwaggerClient::Configuration; +use base "Class::Data::Inheritable"; + +__PACKAGE__->mk_classdata('method_documentation' => {}); + sub new { my $class = shift; - my $default_api_client = $WWW::SwaggerClient::Configuration::api_client ? $WWW::SwaggerClient::Configuration::api_client : WWW::SwaggerClient::ApiClient->new; my (%self) = ( - 'api_client' => $default_api_client, + 'api_client' => WWW::SwaggerClient::ApiClient->instance, @_ ); @@ -47,12 +50,27 @@ sub new { } + # # update_pet # # Update an existing pet # # @param Pet $body Pet object that needs to be added to the store (optional) +{ + my $params = { + 'body' => { + data_type => 'Pet', + description => 'Pet object that needs to be added to the store', + required => '0', + }, + }; + __PACKAGE__->method_documentation->{ update_pet } = { + summary => 'Update an existing pet', + params => $params, + returns => undef, + }; +} # @return void # sub update_pet { @@ -87,7 +105,7 @@ sub update_pet { } # authentication setting, if any - my $auth_settings = ['petstore_auth']; + my $auth_settings = [qw(petstore_auth )]; # make the API Call @@ -97,12 +115,27 @@ sub update_pet { return; } + # # add_pet # # Add a new pet to the store # # @param Pet $body Pet object that needs to be added to the store (optional) +{ + my $params = { + 'body' => { + data_type => 'Pet', + description => 'Pet object that needs to be added to the store', + required => '0', + }, + }; + __PACKAGE__->method_documentation->{ add_pet } = { + summary => 'Add a new pet to the store', + params => $params, + returns => undef, + }; +} # @return void # sub add_pet { @@ -137,7 +170,7 @@ sub add_pet { } # authentication setting, if any - my $auth_settings = ['petstore_auth']; + my $auth_settings = [qw(petstore_auth )]; # make the API Call @@ -147,12 +180,27 @@ sub add_pet { return; } + # # find_pets_by_status # # Finds Pets by status # # @param ARRAY[string] $status Status values that need to be considered for filter (optional) +{ + my $params = { + 'status' => { + data_type => 'ARRAY[string]', + description => 'Status values that need to be considered for filter', + required => '0', + }, + }; + __PACKAGE__->method_documentation->{ find_pets_by_status } = { + summary => 'Finds Pets by status', + params => $params, + returns => 'ARRAY[Pet]', + }; +} # @return ARRAY[Pet] # sub find_pets_by_status { @@ -187,7 +235,7 @@ sub find_pets_by_status { # authentication setting, if any - my $auth_settings = ['petstore_auth']; + my $auth_settings = [qw(petstore_auth )]; # make the API Call my $response = $self->{api_client}->call_api($_resource_path, $_method, @@ -200,12 +248,27 @@ sub find_pets_by_status { return $_response_object; } + # # find_pets_by_tags # # Finds Pets by tags # # @param ARRAY[string] $tags Tags to filter by (optional) +{ + my $params = { + 'tags' => { + data_type => 'ARRAY[string]', + description => 'Tags to filter by', + required => '0', + }, + }; + __PACKAGE__->method_documentation->{ find_pets_by_tags } = { + summary => 'Finds Pets by tags', + params => $params, + returns => 'ARRAY[Pet]', + }; +} # @return ARRAY[Pet] # sub find_pets_by_tags { @@ -240,7 +303,7 @@ sub find_pets_by_tags { # authentication setting, if any - my $auth_settings = ['petstore_auth']; + my $auth_settings = [qw(petstore_auth )]; # make the API Call my $response = $self->{api_client}->call_api($_resource_path, $_method, @@ -253,12 +316,27 @@ sub find_pets_by_tags { return $_response_object; } + # # get_pet_by_id # # Find pet by ID # # @param int $pet_id ID of pet that needs to be fetched (required) +{ + my $params = { + 'pet_id' => { + data_type => 'int', + description => 'ID of pet that needs to be fetched', + required => '1', + }, + }; + __PACKAGE__->method_documentation->{ get_pet_by_id } = { + summary => 'Find pet by ID', + params => $params, + returns => 'Pet', + }; +} # @return Pet # sub get_pet_by_id { @@ -300,7 +378,7 @@ sub get_pet_by_id { # authentication setting, if any - my $auth_settings = ['api_key']; + my $auth_settings = [qw(api_key )]; # make the API Call my $response = $self->{api_client}->call_api($_resource_path, $_method, @@ -313,6 +391,7 @@ sub get_pet_by_id { return $_response_object; } + # # update_pet_with_form # @@ -321,6 +400,30 @@ sub get_pet_by_id { # @param string $pet_id ID of pet that needs to be updated (required) # @param string $name Updated name of the pet (optional) # @param string $status Updated status of the pet (optional) +{ + my $params = { + 'pet_id' => { + data_type => 'string', + description => 'ID of pet that needs to be updated', + required => '1', + }, + 'name' => { + data_type => 'string', + description => 'Updated name of the pet', + required => '0', + }, + 'status' => { + data_type => 'string', + description => 'Updated status of the pet', + required => '0', + }, + }; + __PACKAGE__->method_documentation->{ update_pet_with_form } = { + summary => 'Updates a pet in the store with form data', + params => $params, + returns => undef, + }; +} # @return void # sub update_pet_with_form { @@ -372,7 +475,7 @@ sub update_pet_with_form { # authentication setting, if any - my $auth_settings = ['petstore_auth']; + my $auth_settings = [qw(petstore_auth )]; # make the API Call @@ -382,6 +485,7 @@ sub update_pet_with_form { return; } + # # delete_pet # @@ -389,6 +493,25 @@ sub update_pet_with_form { # # @param int $pet_id Pet id to delete (required) # @param string $api_key (optional) +{ + my $params = { + 'pet_id' => { + data_type => 'int', + description => 'Pet id to delete', + required => '1', + }, + 'api_key' => { + data_type => 'string', + description => '', + required => '0', + }, + }; + __PACKAGE__->method_documentation->{ delete_pet } = { + summary => 'Deletes a pet', + params => $params, + returns => undef, + }; +} # @return void # sub delete_pet { @@ -433,7 +556,7 @@ sub delete_pet { # authentication setting, if any - my $auth_settings = ['petstore_auth']; + my $auth_settings = [qw(petstore_auth )]; # make the API Call @@ -443,6 +566,7 @@ sub delete_pet { return; } + # # upload_file # @@ -451,6 +575,30 @@ sub delete_pet { # @param int $pet_id ID of pet to update (required) # @param string $additional_metadata Additional data to pass to server (optional) # @param file $file file to upload (optional) +{ + my $params = { + 'pet_id' => { + data_type => 'int', + description => 'ID of pet to update', + required => '1', + }, + 'additional_metadata' => { + data_type => 'string', + description => 'Additional data to pass to server', + required => '0', + }, + 'file' => { + data_type => 'file', + description => 'file to upload', + required => '0', + }, + }; + __PACKAGE__->method_documentation->{ upload_file } = { + summary => 'uploads an image', + params => $params, + returns => undef, + }; +} # @return void # sub upload_file { @@ -503,7 +651,7 @@ sub upload_file { # authentication setting, if any - my $auth_settings = ['petstore_auth']; + my $auth_settings = [qw(petstore_auth )]; # make the API Call diff --git a/samples/client/petstore/perl/lib/WWW/SwaggerClient/Role.pm b/samples/client/petstore/perl/lib/WWW/SwaggerClient/Role.pm new file mode 100644 index 000000000000..feb5228cb615 --- /dev/null +++ b/samples/client/petstore/perl/lib/WWW/SwaggerClient/Role.pm @@ -0,0 +1,323 @@ +package WWW::SwaggerClient::Role; +use utf8; + +use Moose::Role; +use namespace::autoclean; +use Class::Inspector; +use Log::Any qw($log); +use WWW::SwaggerClient::ApiFactory; + +has base_url => ( is => 'ro', + required => 0, + isa => 'Str', + documentation => 'Root of the server that requests are sent to', + ); + +has api_factory => ( is => 'ro', + isa => 'WWW::SwaggerClient::ApiFactory', + builder => '_build_af', + lazy => 1, + documentation => 'Builds an instance of the endpoint API class', + ); + +has tokens => ( is => 'ro', + isa => 'HashRef', + required => 0, + default => sub { {} }, + documentation => 'The auth tokens required by the application - basic, OAuth and/or API key(s)', + ); + +has _cfg => ( is => 'ro', + isa => 'Str', + default => 'WWW::SwaggerClient::Configuration', + ); + +has version_info => ( is => 'ro', + isa => 'HashRef', + default => sub { { + app_name => 'Swagger Petstore', + app_version => '1.0.0', + generated_date => '2015-11-13T20:46:43.271Z', + generator_class => 'class io.swagger.codegen.languages.PerlClientCodegen', + } }, + documentation => 'Information about the application version and the codegen codebase version' + ); + +sub BUILD { + my $self = shift; + + $self->_cfg->accept_tokens( $self->tokens ) if keys %{$self->tokens}; + + # ignore these symbols imported into API namespaces + my %outsiders = map {$_ => 1} qw( croak ); + + my %delegates; + + # collect the methods callable on each API + foreach my $api_name ($self->api_factory->apis_available) { + my $api_class = $self->api_factory->classname_for($api_name); + my $methods = Class::Inspector->methods($api_class, 'expanded'); # not Moose, so use CI instead + my @local_methods = grep {! /^_/} grep {! $outsiders{$_}} map {$_->[2]} grep {$_->[1] eq $api_class} @$methods; + push( @{$delegates{$_}}, {api_name => $api_name, api_class => $api_class} ) for @local_methods; + } + + # remove clashes + foreach my $method (keys %delegates) { + if ( @{$delegates{$method}} > 1 ) { + my ($apis) = delete $delegates{$method}; + } + } + + # build the flattened API + foreach my $api_name ($self->api_factory->apis_available) { + my $att_name = sprintf "%s_api", lc($api_name); + my $api_class = $self->api_factory->classname_for($api_name); + my @delegated = grep { $delegates{$_}->[0]->{api_name} eq $api_name } keys %delegates; + $log->debugf("Adding API: '%s' handles %s", $att_name, join ', ', @delegated); + $self->meta->add_attribute( $att_name => ( + is => 'ro', + isa => $api_class, + default => sub {$self->api_factory->get_api($api_name)}, + lazy => 1, + handles => \@delegated, + ) ); + } +} + +sub _build_af { + my $self = shift; + my %args; + $args{base_url} = $self->base_url if $self->base_url; + return WWW::SwaggerClient::ApiFactory->new(%args); +} + +=head1 NAME + +WWW::SwaggerClient::Role - a Moose role for the Swagger Petstore + +=head2 Swagger Petstore version: 1.0.0 + +=head1 VERSION + +Automatically generated by the Perl Swagger Codegen project: + +=over 4 + +=item Build date: 2015-11-13T20:46:43.271Z + +=item Build package: class io.swagger.codegen.languages.PerlClientCodegen + +=item Codegen version: + +=back + +=head2 A note on Moose + +This role is the only component of the library that uses Moose. See +WWW::SwaggerClient::ApiFactory for non-Moosey usage. + +=head1 SYNOPSIS + +The Perl Swagger Codegen project builds a library of Perl modules to interact with +a web service defined by a Swagger specification. See below for how to build the +library. + +This module provides an interface to the generated library. All the classes, +objects, and methods (well, not quite *all*, see below) are flattened into this +role. + + package MyApp; + use Moose; + with 'WWW::SwaggerClient::Role'; + + package main; + + my $api = MyApp->new({ tokens => $tokens }); + + my $pet = $api->get_pet_by_id(pet_id => $pet_id); + +=head2 Structure of the library + +The library consists of a set of API classes, one for each endpoint. These APIs +implement the method calls available on each endpoint. + +Additionally, there is a set of "object" classes, which represent the objects +returned by and sent to the methods on the endpoints. + +An API factory class is provided, which builds instances of each endpoint API. + +This Moose role flattens all the methods from the endpoint APIs onto the consuming +class. It also provides methods to retrieve the endpoint API objects, and the API +factory object, should you need it. + +For documentation of all these methods, see AUTOMATIC DOCUMENTATION below. + +=head2 Configuring authentication + +In the normal case, the Swagger spec will describe what parameters are +required and where to put them. You just need to supply the tokens. + + my $tokens = { + # basic + username => $username, + password => $password, + + # oauth + access_token => $oauth_token, + + # keys + $some_key => { token => $token, + prefix => $prefix, + in => $in, # 'head||query', + }, + + $another => { token => $token, + prefix => $prefix, + in => $in, # 'head||query', + }, + ..., + + }; + + my $api = MyApp->new({ tokens => $tokens }); + +Note these are all optional, as are C and C, and depend on the API +you are accessing. Usually C and C will be determined by the code generator from +the spec and you will not need to set them at run time. If not, C will +default to 'head' and C to the empty string. + +The tokens will be placed in the C namespace +as follows, but you don't need to know about this. + +=over 4 + +=item C<$WWW::SwaggerClient::Configuration::username> + +String. The username for basic auth. + +=item C<$WWW::SwaggerClient::Configuration::password> + +String. The password for basic auth. + +=item C<$WWW::SwaggerClient::Configuration::api_key> + +Hashref. Keyed on the name of each key (there can be multiple tokens). + + $WWW::SwaggerClient::Configuration::api_key = { + secretKey => 'aaaabbbbccccdddd', + anotherKey => '1111222233334444', + }; + +=item C<$WWW::SwaggerClient::Configuration::api_key_prefix> + +Hashref. Keyed on the name of each key (there can be multiple tokens). Note not +all api keys require a prefix. + + $WWW::SwaggerClient::Configuration::api_key_prefix = { + secretKey => 'string', + anotherKey => 'same or some other string', + }; + +=item C<$WWW::SwaggerClient::Configuration::access_token> + +String. The OAuth access token. + +=back + +=head1 METHODS + +=head2 C + +The generated code has the C already set as a default value. This method +returns (and optionally sets, but only if the API client has not been +created yet) the current value of C. + +=head2 C + +Returns an API factory object. You probably won't need to call this directly. + + $self->api_factory('Pet'); # returns a WWW::SwaggerClient::PetApi instance + + $self->pet_api; # the same + +=head1 MISSING METHODS + +Most of the methods on the API are delegated to individual endpoint API objects +(e.g. Pet API, Store API, User API etc). Where different endpoint APIs use the +same method name (e.g. C), these methods can't be delegated. So you need +to call C<$api-Epet_api-Enew()>. + +In principle, every API is susceptible to the presence of a few, random, undelegatable +method names. In practice, because of the way method names are constructed, it's +unlikely in general that any methods will be undelegatable, except for: + + new() + class_documentation() + method_documentation() + +To call these methods, you need to get a handle on the relevant object, either +by calling C<$api-Efoo_api> or by retrieving an object, e.g. +C<$api-Eget_pet_by_id(pet_id =E $pet_id)>. They are class methods, so +you could also call them on class names. + +=head1 BUILDING YOUR LIBRARY + +See the homepage C for full details. +But briefly, clone the git repository, build the codegen codebase, set up your build +config file, then run the API build script. You will need git, Java 7 and Apache +maven 3.0.3 or better already installed. + +The config file should specify the project name for the generated library: + + {"moduleName":"MyProjectName"} + +Your library files will be built under C. + + $ git clone https://github.com/swagger-api/swagger-codegen.git + $ cd swagger-codegen + $ mvn package + $ java -jar modules/swagger-codegen-cli/target/swagger-codegen-cli.jar generate \ + -i [URL or file path to JSON swagger API spec] \ + -l perl \ + -c /path/to/config/file.json \ + -o /path/to/output/folder + +Bang, all done. Run the C script in the C directory to see the API +you just built. + +=head1 AUTOMATIC DOCUMENTATION + +You can print out a summary of the generated API by running the included +C script in the C directory of your generated library. A few +output formats are supported: + + Usage: autodoc [OPTION] + + -w wide format (default) + -n narrow format + -p POD format + -H HTML format + -m Markdown format + -h print this help message + -c your application class + +The C<-c> option allows you to load and inspect your own application. A dummy +namespace is used if you don't supply your own class. + +=head1 DOCUMENTATION FROM THE SWAGGER SPEC + +Additional documentation for each class and method may be provided by the Swagger +spec. If so, this is available via the C and +C methods on each generated object class, and the +C method on the endpoint API classes: + + my $cmdoc = $api->pet_api->method_documentation->{$method_name}; + + my $odoc = $api->get_pet_by_id->(pet_id => $pet_id)->class_documentation; + my $omdoc = $api->get_pet_by_id->(pet_id => $pet_id)->method_documentation->{method_name}; + +Each of these calls returns a hashref with various useful pieces of information. + +=cut + +1; diff --git a/samples/client/petstore/perl/lib/WWW/SwaggerClient/Role/AutoDoc.pm b/samples/client/petstore/perl/lib/WWW/SwaggerClient/Role/AutoDoc.pm new file mode 100644 index 000000000000..0dc30dbfb902 --- /dev/null +++ b/samples/client/petstore/perl/lib/WWW/SwaggerClient/Role/AutoDoc.pm @@ -0,0 +1,427 @@ +package WWW::SwaggerClient::Role::AutoDoc; +use List::MoreUtils qw(uniq); + +use Moose::Role; + +sub autodoc { + my ($self, $how) = @_; + + die "Unknown format '$how'" unless $how =~ /^(pod|wide|narrow)$/; + + $self->_printisa($how); + $self->_printmethods($how); + $self->_printattrs($how); + print "\n"; +} + +sub _printisa { + my ($self, $how) = @_; + my $meta = $self->meta; + + my $myclass = ref $self; + + my $super = join ', ', $meta->superclasses; + my @roles = $meta->calculate_all_roles; + #shift(@roles) if @roles > 1; # if > 1, the first is a composite, the rest are the roles + + my $isa = join ', ', grep {$_ ne $myclass} $meta->linearized_isa; + my $sub = join ', ', $meta->subclasses; + my $dsub = join ', ', $meta->direct_subclasses; + + my $app_name = $self->version_info->{app_name}; + my $app_version = $self->version_info->{app_version}; + my $generated_date = $self->version_info->{generated_date}; + my $generator_class = $self->version_info->{generator_class}; + + $~ = $how eq 'pod' ? 'INHERIT_POD' : 'INHERIT'; + write; + + my ($rolepkg, $role_reqs); + + foreach my $role (@roles) { + $rolepkg = $role->{package} || next; # some are anonymous, or something + next if $rolepkg eq 'WWW::SwaggerClient::Role::AutoDoc'; + $role_reqs = join ', ', keys %{$role->{required_methods}}; + $role_reqs ||= ''; + $~ = $how eq 'pod' ? 'ROLES_POD' : 'ROLES'; + write; + } + + if ($how eq 'pod') { + $~ = 'ROLES_POD_CLOSE'; + write; + } + +# ----- format specs ----- + format INHERIT = + +@* - +$myclass + ISA: @* + $isa + Direct subclasses: @* + $dsub + All subclasses: @* + $sub + + Target API: @* @* + $app_name, $app_version + Generated on: @* + $generated_date + Generator class: @* + $generator_class + +. + format ROLES = + Composes: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~ + $rolepkg + requires: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~ + $role_reqs + ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~~ + $role_reqs +. + + format INHERIT_POD = +=head1 NAME + +@* +$myclass + +=head1 VERSION + +=head2 @* version: @* + $app_name, $app_version + +Automatically generated by the Perl Swagger Codegen project: + +=over 4 + +=item Build date: @* + $generated_date + +=item Build package: @* + $generator_class + +=item Codegen version: + + +=back + +=head1 INHERITANCE + +=head2 Base class(es) + +@* +$isa + +=head2 Direct subclasses + +@* +$dsub + +=head2 All subclasses + +@* +$sub + + +=head1 COMPOSITION + +@* composes the following roles: +$myclass + + +. + format ROLES_POD = +=head2 C<@*> + $rolepkg + +Requires: + +@* +$role_reqs + +. + format ROLES_POD_CLOSE = + + +. +# ----- / format specs ----- +} + +sub _printmethods { + my ($self, $how) = @_; + + if ($how eq 'narrow') { + print <_printmethod($_, $how) for uniq sort $self->meta->get_all_method_names; #$self->meta->get_method_list, + + if ($how eq 'pod') { + $~ = 'METHOD_POD_CLOSE'; + write; + } + + +} + +sub _printmethod { + my ($self, $methodname, $how) = @_; + return if $methodname =~ /^_/; + return if $self->meta->has_attribute($methodname); + my %internal = map {$_ => 1} qw(BUILD BUILDARGS meta can new DEMOLISHALL DESTROY + DOES isa BUILDALL does VERSION dump + ); + return if $internal{$methodname}; + my $method = $self->meta->get_method($methodname) or return; # symbols imported into namespaces i.e. not known by Moose + + return if $method->original_package_name eq __PACKAGE__; + + my $delegate_to = ''; + my $via = ''; + my $on = ''; + my $doc = ''; + my $original_pkg = $method->original_package_name; + if ($method->can('associated_attribute')) { + $delegate_to = $method->delegate_to_method; + my $aa = $method->associated_attribute; + $on = $aa->{isa}; + $via = $aa->{name}; + $original_pkg = $on; + $doc = $original_pkg->method_documentation->{$delegate_to}->{summary}; + } + else { + $doc = $method->documentation; + } + + if ($how eq 'narrow') { + $~ = 'METHOD_NARROW'; + write; + } + elsif ($how eq 'pod' and $delegate_to) { + $~ = 'METHOD_POD_DELEGATED'; + write; + } + elsif ($how eq 'pod') { + $~ = 'METHOD_POD'; + write; + } + else { + $~ = 'METHOD'; + write; + } + +# ----- format specs ----- + format METHODHEAD = + +METHODS +------- +Name delegates to on via +=========================================================================================================================================================================== +. + format METHOD = +@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<... @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<... @<<<<<<<<<<<<<<<<... +$methodname, $delegate_to, $on, $via +. + + format METHOD_NARROW = +@* +$methodname + original pkg: @* + $original_pkg + delegates to: @* + $delegate_to + on: @* + $on + via: @* + $via + +. + + format METHODHEAD_POD = + +=head1 METHODS + +. + + format METHOD_POD = + +=head2 C<@*()> + $methodname + + Defined in: @* + $original_pkg + + +. + format METHOD_POD_DELEGATED = + +=head2 C<@*()> + $methodname + + Defined in: @* + $original_pkg + Delegates to: @*() + $delegate_to + On: @* + $on + Via: @*() + $via + Doc: @* + $doc + Same as: $self->@*->@*() + $via, $delegate_to + +. + format METHOD_POD_CLOSE = + +. +# ----- / format specs ----- +} + +sub _printattrs { + my ($self, $how) = @_; + + if ($how eq 'narrow') { + print <_printattr($_, $how) for sort $self->meta->get_attribute_list; + + if ($how eq 'pod') { + $~ = 'ATTR_POD_CLOSE'; + write; + } +} + +sub _printattr { + my ($self, $attrname, $how) = @_; + return if $attrname =~ /^_/; + my $attr = $self->meta->get_attribute($attrname) or die "No attr for $attrname"; + + my $is; + $is = 'rw' if $attr->get_read_method && $attr->get_write_method; + $is = 'ro' if $attr->get_read_method && ! $attr->get_write_method; + $is = 'wo' if $attr->get_write_method && ! $attr->get_read_method; + $is = '--' if ! $attr->get_write_method && ! $attr->get_read_method; + $is or die "No \$is for $attrname"; + + my $tc = $attr->type_constraint || ''; + my $from = $attr->associated_class->name || ''; + my $reqd = $attr->is_required ? 'yes' : 'no'; + my $lazy = $attr->is_lazy ? 'yes' : 'no'; + my $has_doc = $attr->has_documentation ? 'yes' : 'no'; # *_api attributes will never have doc, but other attributes might have + my $doc = $attr->documentation || ''; + my $handles = join ', ', sort @{$attr->handles || []}; + $handles ||= ''; + + if ($how eq 'narrow') { + $~ = 'ATTR_NARROW'; + } + elsif ($how eq 'pod') { + $~ = 'ATTR_POD'; + } + else { + $~ = 'ATTR'; + } + + write; + +# ----- format specs ----- + format ATTRHEAD = + +ATTRIBUTES +---------- +Name is isa reqd lazy doc handles +============================================================================================================== +. + format ATTR = +@<<<<<<<<<<<<<<<<< @< @<<<<<<<<<<<<<<<<<<<<<<<< @<<< @<<< @<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +$attrname, $is, $tc, $reqd, $lazy, $has_doc, $handles + ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~~ + $handles +. + + format ATTR_NARROW = +@* +$attrname + is: @* + $is + isa: @* + $tc + reqd: @* + $reqd + lazy: @* + $lazy + doc: @* + $doc + handles: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + $handles + ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~~ + $handles + +. + format ATTRHEAD_POD = +=head1 ATTRIBUTES + +. + format ATTR_POD = + +=head2 C<@*> + $attrname + + is: @* + $is + isa: @* + $tc + reqd: @* + $reqd + lazy: @* + $lazy + doc: @* + $doc + handles: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + $handles + ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~~ + $handles + +. + format ATTR_POD_CLOSE = + + +. +# ----- / format specs ----- +} + + + +1; \ No newline at end of file diff --git a/samples/client/petstore/perl/lib/WWW/SwaggerClient/StoreApi.pm b/samples/client/petstore/perl/lib/WWW/SwaggerClient/StoreApi.pm index a2ac9010e779..abe936573e7c 100644 --- a/samples/client/petstore/perl/lib/WWW/SwaggerClient/StoreApi.pm +++ b/samples/client/petstore/perl/lib/WWW/SwaggerClient/StoreApi.pm @@ -30,11 +30,14 @@ use Log::Any qw($log); use WWW::SwaggerClient::ApiClient; use WWW::SwaggerClient::Configuration; +use base "Class::Data::Inheritable"; + +__PACKAGE__->mk_classdata('method_documentation' => {}); + sub new { my $class = shift; - my $default_api_client = $WWW::SwaggerClient::Configuration::api_client ? $WWW::SwaggerClient::Configuration::api_client : WWW::SwaggerClient::ApiClient->new; my (%self) = ( - 'api_client' => $default_api_client, + 'api_client' => WWW::SwaggerClient::ApiClient->instance, @_ ); @@ -47,11 +50,21 @@ sub new { } + # # get_inventory # # Returns pet inventories by status # +{ + my $params = { + }; + __PACKAGE__->method_documentation->{ get_inventory } = { + summary => 'Returns pet inventories by status', + params => $params, + returns => 'HASH[string,int]', + }; +} # @return HASH[string,int] # sub get_inventory { @@ -83,7 +96,7 @@ sub get_inventory { # authentication setting, if any - my $auth_settings = ['api_key']; + my $auth_settings = [qw(api_key )]; # make the API Call my $response = $self->{api_client}->call_api($_resource_path, $_method, @@ -96,12 +109,27 @@ sub get_inventory { return $_response_object; } + # # place_order # # Place an order for a pet # # @param Order $body order placed for purchasing the pet (optional) +{ + my $params = { + 'body' => { + data_type => 'Order', + description => 'order placed for purchasing the pet', + required => '0', + }, + }; + __PACKAGE__->method_documentation->{ place_order } = { + summary => 'Place an order for a pet', + params => $params, + returns => 'Order', + }; +} # @return Order # sub place_order { @@ -136,7 +164,7 @@ sub place_order { } # authentication setting, if any - my $auth_settings = []; + my $auth_settings = [qw()]; # make the API Call my $response = $self->{api_client}->call_api($_resource_path, $_method, @@ -149,12 +177,27 @@ sub place_order { return $_response_object; } + # # get_order_by_id # # Find purchase order by ID # # @param string $order_id ID of pet that needs to be fetched (required) +{ + my $params = { + 'order_id' => { + data_type => 'string', + description => 'ID of pet that needs to be fetched', + required => '1', + }, + }; + __PACKAGE__->method_documentation->{ get_order_by_id } = { + summary => 'Find purchase order by ID', + params => $params, + returns => 'Order', + }; +} # @return Order # sub get_order_by_id { @@ -196,7 +239,7 @@ sub get_order_by_id { # authentication setting, if any - my $auth_settings = []; + my $auth_settings = [qw()]; # make the API Call my $response = $self->{api_client}->call_api($_resource_path, $_method, @@ -209,12 +252,27 @@ sub get_order_by_id { return $_response_object; } + # # delete_order # # Delete purchase order by ID # # @param string $order_id ID of the order that needs to be deleted (required) +{ + my $params = { + 'order_id' => { + data_type => 'string', + description => 'ID of the order that needs to be deleted', + required => '1', + }, + }; + __PACKAGE__->method_documentation->{ delete_order } = { + summary => 'Delete purchase order by ID', + params => $params, + returns => undef, + }; +} # @return void # sub delete_order { @@ -256,7 +314,7 @@ sub delete_order { # authentication setting, if any - my $auth_settings = []; + my $auth_settings = [qw()]; # make the API Call diff --git a/samples/client/petstore/perl/lib/WWW/SwaggerClient/UserApi.pm b/samples/client/petstore/perl/lib/WWW/SwaggerClient/UserApi.pm index e1088a0839e0..9ba45815c8ce 100644 --- a/samples/client/petstore/perl/lib/WWW/SwaggerClient/UserApi.pm +++ b/samples/client/petstore/perl/lib/WWW/SwaggerClient/UserApi.pm @@ -30,11 +30,14 @@ use Log::Any qw($log); use WWW::SwaggerClient::ApiClient; use WWW::SwaggerClient::Configuration; +use base "Class::Data::Inheritable"; + +__PACKAGE__->mk_classdata('method_documentation' => {}); + sub new { my $class = shift; - my $default_api_client = $WWW::SwaggerClient::Configuration::api_client ? $WWW::SwaggerClient::Configuration::api_client : WWW::SwaggerClient::ApiClient->new; my (%self) = ( - 'api_client' => $default_api_client, + 'api_client' => WWW::SwaggerClient::ApiClient->instance, @_ ); @@ -47,12 +50,27 @@ sub new { } + # # create_user # # Create user # # @param User $body Created user object (optional) +{ + my $params = { + 'body' => { + data_type => 'User', + description => 'Created user object', + required => '0', + }, + }; + __PACKAGE__->method_documentation->{ create_user } = { + summary => 'Create user', + params => $params, + returns => undef, + }; +} # @return void # sub create_user { @@ -87,7 +105,7 @@ sub create_user { } # authentication setting, if any - my $auth_settings = []; + my $auth_settings = [qw()]; # make the API Call @@ -97,12 +115,27 @@ sub create_user { return; } + # # create_users_with_array_input # # Creates list of users with given input array # # @param ARRAY[User] $body List of user object (optional) +{ + my $params = { + 'body' => { + data_type => 'ARRAY[User]', + description => 'List of user object', + required => '0', + }, + }; + __PACKAGE__->method_documentation->{ create_users_with_array_input } = { + summary => 'Creates list of users with given input array', + params => $params, + returns => undef, + }; +} # @return void # sub create_users_with_array_input { @@ -137,7 +170,7 @@ sub create_users_with_array_input { } # authentication setting, if any - my $auth_settings = []; + my $auth_settings = [qw()]; # make the API Call @@ -147,12 +180,27 @@ sub create_users_with_array_input { return; } + # # create_users_with_list_input # # Creates list of users with given input array # # @param ARRAY[User] $body List of user object (optional) +{ + my $params = { + 'body' => { + data_type => 'ARRAY[User]', + description => 'List of user object', + required => '0', + }, + }; + __PACKAGE__->method_documentation->{ create_users_with_list_input } = { + summary => 'Creates list of users with given input array', + params => $params, + returns => undef, + }; +} # @return void # sub create_users_with_list_input { @@ -187,7 +235,7 @@ sub create_users_with_list_input { } # authentication setting, if any - my $auth_settings = []; + my $auth_settings = [qw()]; # make the API Call @@ -197,6 +245,7 @@ sub create_users_with_list_input { return; } + # # login_user # @@ -204,6 +253,25 @@ sub create_users_with_list_input { # # @param string $username The user name for login (optional) # @param string $password The password for login in clear text (optional) +{ + my $params = { + 'username' => { + data_type => 'string', + description => 'The user name for login', + required => '0', + }, + 'password' => { + data_type => 'string', + description => 'The password for login in clear text', + required => '0', + }, + }; + __PACKAGE__->method_documentation->{ login_user } = { + summary => 'Logs user into the system', + params => $params, + returns => 'string', + }; +} # @return string # sub login_user { @@ -241,7 +309,7 @@ sub login_user { # authentication setting, if any - my $auth_settings = []; + my $auth_settings = [qw()]; # make the API Call my $response = $self->{api_client}->call_api($_resource_path, $_method, @@ -254,11 +322,21 @@ sub login_user { return $_response_object; } + # # logout_user # # Logs out current logged in user session # +{ + my $params = { + }; + __PACKAGE__->method_documentation->{ logout_user } = { + summary => 'Logs out current logged in user session', + params => $params, + returns => undef, + }; +} # @return void # sub logout_user { @@ -290,7 +368,7 @@ sub logout_user { # authentication setting, if any - my $auth_settings = []; + my $auth_settings = [qw()]; # make the API Call @@ -300,12 +378,27 @@ sub logout_user { return; } + # # get_user_by_name # # Get user by user name # # @param string $username The name that needs to be fetched. Use user1 for testing. (required) +{ + my $params = { + 'username' => { + data_type => 'string', + description => 'The name that needs to be fetched. Use user1 for testing.', + required => '1', + }, + }; + __PACKAGE__->method_documentation->{ get_user_by_name } = { + summary => 'Get user by user name', + params => $params, + returns => 'User', + }; +} # @return User # sub get_user_by_name { @@ -347,7 +440,7 @@ sub get_user_by_name { # authentication setting, if any - my $auth_settings = []; + my $auth_settings = [qw()]; # make the API Call my $response = $self->{api_client}->call_api($_resource_path, $_method, @@ -360,6 +453,7 @@ sub get_user_by_name { return $_response_object; } + # # update_user # @@ -367,6 +461,25 @@ sub get_user_by_name { # # @param string $username name that need to be deleted (required) # @param User $body Updated user object (optional) +{ + my $params = { + 'username' => { + data_type => 'string', + description => 'name that need to be deleted', + required => '1', + }, + 'body' => { + data_type => 'User', + description => 'Updated user object', + required => '0', + }, + }; + __PACKAGE__->method_documentation->{ update_user } = { + summary => 'Updated user', + params => $params, + returns => undef, + }; +} # @return void # sub update_user { @@ -411,7 +524,7 @@ sub update_user { } # authentication setting, if any - my $auth_settings = []; + my $auth_settings = [qw()]; # make the API Call @@ -421,12 +534,27 @@ sub update_user { return; } + # # delete_user # # Delete user # # @param string $username The name that needs to be deleted (required) +{ + my $params = { + 'username' => { + data_type => 'string', + description => 'The name that needs to be deleted', + required => '1', + }, + }; + __PACKAGE__->method_documentation->{ delete_user } = { + summary => 'Delete user', + params => $params, + returns => undef, + }; +} # @return void # sub delete_user { @@ -468,7 +596,7 @@ sub delete_user { # authentication setting, if any - my $auth_settings = []; + my $auth_settings = [qw()]; # make the API Call diff --git a/samples/client/petstore/perl/pom.xml b/samples/client/petstore/perl/pom.xml index 4034cf0a6871..4aa0040f82e7 100644 --- a/samples/client/petstore/perl/pom.xml +++ b/samples/client/petstore/perl/pom.xml @@ -65,6 +65,19 @@ + + Test::More for Role + integration-test + + exec + + + perl + + t/04_role.t + + + diff --git a/samples/client/petstore/perl/t/01_pet_api.t b/samples/client/petstore/perl/t/01_pet_api.t index 5460c3282b26..c7bcdf98a0aa 100644 --- a/samples/client/petstore/perl/t/01_pet_api.t +++ b/samples/client/petstore/perl/t/01_pet_api.t @@ -1,4 +1,4 @@ -use Test::More tests => 37; +use Test::More tests => 38; use Test::Exception; use lib 'lib'; @@ -11,12 +11,18 @@ use_ok('WWW::SwaggerClient::Object::Pet'); use_ok('WWW::SwaggerClient::Object::Tag'); use_ok('WWW::SwaggerClient::Object::Category'); -my $api_client = WWW::SwaggerClient::ApiClient->new('base_url' => 'http://testing'); +my $api_client = WWW::SwaggerClient::ApiClient->instance('base_url' => 'http://testing'); my $pet_api = WWW::SwaggerClient::PetApi->new('api_client' => $api_client); is $pet_api->{api_client}->{base_url}, 'http://testing', 'get the proper base URL from api client'; my $api = WWW::SwaggerClient::PetApi->new(); +is $api->{api_client}->{base_url}, 'http://testing', 'we still get the original base URL from api client, because it\'s a singleton'; + +# reset the base_url - no direct access because an application shouldn't be changing +# its base URL halfway through +$api->{api_client}->{base_url} = 'http://petstore.swagger.io/v2'; + is $api->{api_client}->{base_url}, 'http://petstore.swagger.io/v2', 'get the default base URL from api client'; # test select_header_content_type diff --git a/samples/client/petstore/perl/t/02_store_api.t b/samples/client/petstore/perl/t/02_store_api.t index dfee5c468398..39b18381b0e7 100644 --- a/samples/client/petstore/perl/t/02_store_api.t +++ b/samples/client/petstore/perl/t/02_store_api.t @@ -15,7 +15,7 @@ use_ok('WWW::SwaggerClient::Object::Category'); use_ok('WWW::SwaggerClient::Object::User'); -my $api_client = WWW::SwaggerClient::ApiClient->new(); +my $api_client = WWW::SwaggerClient::ApiClient->instance(); my $store_api = WWW::SwaggerClient::StoreApi->new('api_client' => $api_client); is $store_api->{api_client}->{base_url}, 'http://petstore.swagger.io/v2', 'get the default base URL from api client'; diff --git a/samples/client/petstore/perl/t/03_api_factory.t b/samples/client/petstore/perl/t/03_api_factory.t index f96bffa7a842..a06805e2bcfe 100644 --- a/samples/client/petstore/perl/t/03_api_factory.t +++ b/samples/client/petstore/perl/t/03_api_factory.t @@ -1,4 +1,4 @@ -use Test::More tests => 13; +use Test::More tests => 19; use Test::Exception; use lib 'lib'; @@ -15,6 +15,9 @@ is $pet_api->{api_client}->{base_url}, 'http://testing', 'get the proper base UR $api_factory = WWW::SwaggerClient::ApiFactory->new; $pet_api = $api_factory->get_api('Pet'); +# reset the base_url - no direct access because an application shouldn't be changing +# its base URL halfway through +$pet_api->{api_client}->{base_url} = 'http://petstore.swagger.io/v2'; is $pet_api->{api_client}->{base_url}, 'http://petstore.swagger.io/v2', 'get the default base URL from api client'; # test accessor methods @@ -32,3 +35,15 @@ is $pet->category->id, '22', 'got the proper category id'; is $pet->category->name, 'perl', 'got the proper category name'; is $pet->tags->[0]->name, 'just kidding', 'got the proper tag name'; is $pet->tags->[0]->id, '11', 'got the proper tag id'; + + +my $add_pet = $pet_api->add_pet(body => $pet); +my $get_pet = $pet_api->get_pet_by_id(pet_id => $pet_id); + +is $get_pet->id, '10008', 'stored and retrieved: got the proper pet id'; +is $get_pet->name, 'perl test', 'stored and retrieved: got the proper pet name'; +is $get_pet->category->id, '22', 'stored and retrieved: got the proper category id'; +is $get_pet->category->name, 'perl', 'stored and retrieved: got the proper category name'; +is $get_pet->tags->[0]->name, 'just kidding', 'stored and retrieved: got the proper tag name'; +is $get_pet->tags->[0]->id, '11', 'stored and retrieved: got the proper tag id'; + diff --git a/samples/client/petstore/perl/t/04_role.t b/samples/client/petstore/perl/t/04_role.t new file mode 100644 index 000000000000..73328fa6e629 --- /dev/null +++ b/samples/client/petstore/perl/t/04_role.t @@ -0,0 +1,143 @@ +use Test::More tests => 37; +use Test::Exception; +use Test::Warnings 'warnings'; +use Test::Deep; + +use lib 'lib'; +use strict; +use warnings; + +SKIP: { + eval " + package MyApp; + use Moose; + with 'WWW::SwaggerClient::Role'; + sub auth_setup_handler {} + "; + +# die $@ if $@; + skip 'Moose not installed', 37 if $@; + +my $api = MyApp->new; + +my $pet_id = 10008; +# note - we don't need to 'use' these modules because they've already been loaded by ApiFactory +my ($category, $tag, $pet); +lives_ok { $category = WWW::SwaggerClient::Object::Category->new('id' => '22', 'name' => 'perl') } 'Category.pm loaded OK'; +lives_ok { $tag = WWW::SwaggerClient::Object::Tag->new('id' => '11', 'name' => 'just kidding') } 'Tag.pm loaded OK'; +lives_ok { $pet = WWW::SwaggerClient::Object::Pet->new('id' => $pet_id, 'name' => 'perl test', + "photoUrls" => ['123', 'oop'], 'tags' => [$tag], 'status' => 'pending', 'category' => $category) } 'Pet.pm loaded OK'; + +is $pet->id, '10008', 'got the proper pet id'; +is $pet->name, 'perl test', 'got the proper pet name'; +is $pet->category->id, '22', 'got the proper category id'; +is $pet->category->name, 'perl', 'got the proper category name'; +is $pet->tags->[0]->name, 'just kidding', 'got the proper tag name'; +is $pet->tags->[0]->id, '11', 'got the proper tag id'; + + +my $add_pet = $api->add_pet(body => $pet); +my $get_pet = $api->get_pet_by_id(pet_id => $pet_id); + +is $get_pet->id, '10008', 'stored and retrieved: got the proper pet id'; +is $get_pet->name, 'perl test', 'stored and retrieved: got the proper pet name'; +is $get_pet->category->id, '22', 'stored and retrieved: got the proper category id'; +is $get_pet->category->name, 'perl', 'stored and retrieved: got the proper category name'; +is $get_pet->tags->[0]->name, 'just kidding', 'stored and retrieved: got the proper tag name'; +is $get_pet->tags->[0]->id, '11', 'stored and retrieved: got the proper tag id'; + +# documentation tests + +# API method docs +is_deeply( [sort keys %{$api->pet_api->method_documentation}], + [ 'add_pet', 'delete_pet', 'find_pets_by_status', 'find_pets_by_tags', 'get_pet_by_id', 'update_pet', 'update_pet_with_form', 'upload_file'], + "Pet API method_documentation has the correct keys"); +is $api->pet_api->method_documentation->{get_pet_by_id}->{params}->{pet_id}->{description}, + 'ID of pet that needs to be fetched', 'get_pet_by_id parameter pet_id description is correct'; +is $api->pet_api->method_documentation->{get_pet_by_id}->{params}->{pet_id}->{required}, + 1, 'get_pet_by_id parameter pet_id is required'; +is $api->pet_api->method_documentation->{get_pet_by_id}->{params}->{pet_id}->{data_type}, + 'int', 'get_pet_by_id parameter pet_id is an int'; +is $api->pet_api->method_documentation->{get_pet_by_id}->{returns}, + 'Pet', 'get_pet_by_id returns a Pet'; +is $api->pet_api->method_documentation->{get_pet_by_id}->{summary}, + 'Find pet by ID', 'get_pet_by_id summary is correct'; + +# object class docs +my $pet_class_doco = { 'description' => '', required => [], class => 'Pet' }; +is_deeply($get_pet->class_documentation, $pet_class_doco, 'Pet object class_documentation is available'); +is $get_pet->class_documentation->{description}, '', 'Pet object class_documentation is correct'; # right now it's blank +is $get_pet->class_documentation->{class}, 'Pet', 'Pet object class_documentation returns correct class name'; + +# object method docs +is $get_pet->method_documentation->{status}->{description}, 'pet status in the store', 'Pet object method_documentation for status() - description is correct'; +is $get_pet->method_documentation->{status}->{format}, '', 'Pet object method_documentation for status() - format is correct'; +is $get_pet->method_documentation->{status}->{base_name}, 'status', 'Pet object method_documentation for status() - base_name is correct'; +is $get_pet->method_documentation->{status}->{datatype}, 'string', 'Pet object method_documentation for status() - datatype is correct'; + + + +# / documentation tests + +my $tokens = { + username => 'UserName', + password => 'PassWord', + access_token => 'OAuth_token', + + someKey => { token => 'some_key_token', + prefix => 'some_key_prefix', + in => 'query', + }, + + anotherKey => { token => 'another_key_token', + }, + }; + +$api->_cfg->accept_tokens({%$tokens}); # pass a copy +no warnings 'once'; +is $WWW::SwaggerClient::Configuration::username, 'UserName', 'accept_tokens() correctly set the username'; +is $WWW::SwaggerClient::Configuration::password, 'PassWord', 'accept_tokens() correctly set the password'; +is $WWW::SwaggerClient::Configuration::access_token, 'OAuth_token', 'accept_tokens() correctly set the oauth'; + +my $api_key_href = { + 'anotherKey' => 'another_key_token', + 'someKey' => 'some_key_token' + }; +cmp_deeply( $WWW::SwaggerClient::Configuration::api_key, $api_key_href, 'accept_tokens() correctly set api_key' ); + +my $api_key_prefix_href = { + 'someKey' => 'some_key_prefix' + }; +cmp_deeply( $WWW::SwaggerClient::Configuration::api_key_prefix, $api_key_prefix_href, 'accept_tokens() correctly set api_key_prefix' ); + +my $api_key_in = { + 'someKey' => 'query', + 'anotherKey' => 'head' + }; +cmp_deeply( $WWW::SwaggerClient::Configuration::api_key_in, $api_key_in, 'accept_tokens() correctly set api_key_in' ); + +use warnings 'once'; + +my $cleared_tokens_cmp = { + 'anotherKey' => { + 'in' => 'head', + 'token' => 'another_key_token', + 'prefix' => undef + }, + 'access_token' => 'OAuth_token', + 'someKey' => { + 'token' => 'some_key_token', + 'in' => 'query', + 'prefix' => 'some_key_prefix' + }, + 'username' => 'UserName', + 'password' => 'PassWord' + }; +cmp_deeply( $api->_cfg->clear_tokens, $cleared_tokens_cmp, 'clear_tokens() returns the correct data structure' ); + +my $bad_token = { bad_token_name => 'bad token value' }; # value should should be hashref +dies_ok { $api->_cfg->accept_tokens($bad_token) } "bad token causes exception"; + + +} # / SKIP +