Handle missing security spec more elegantly

- remove the optional auth_setup_handler() callback mechanism
- add _global_auth_setup() method on ApiClient to analyse config when
security spec not provided
- add methods on the Configuration class to abstract getting and setting
tokens
This commit is contained in:
Dave Baird 2015-11-11 13:43:40 +01:00
parent 06db67210c
commit 2144cf5d31
13 changed files with 461 additions and 293 deletions

View File

@ -34,6 +34,8 @@ sub _new_instance
return bless \%args, $class; return bless \%args, $class;
} }
sub _cfg {'WWW::{{moduleName}}::Configuration'}
# Set the user agent of the API client # Set the user agent of the API client
# #
# @param string $user_agent The user agent of the API client # @param string $user_agent The user agent of the API client
@ -308,18 +310,8 @@ sub get_api_key_with_prefix
sub update_params_for_auth { sub update_params_for_auth {
my ($self, $header_params, $query_params, $auth_settings) = @_; my ($self, $header_params, $query_params, $auth_settings) = @_;
# we can defer to the application if the spec doesn't describe authentication return $self->_global_auth_setup($header_params, $query_params)
if ($self->{auth_setup_handler_object}) { unless $auth_settings && @$auth_settings;
$self->{auth_setup_handler_object}->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);
# one endpoint can have more than 1 auth settings # one endpoint can have more than 1 auth settings
foreach my $auth (@$auth_settings) { foreach my $auth (@$auth_settings) {
@ -332,10 +324,47 @@ sub update_params_for_auth {
} }
{{/authMethods}} {{/authMethods}}
else { 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; 1;

View File

@ -16,6 +16,7 @@ our $http_user_agent = 'Perl-Swagger';
# authenticaiton setting # authenticaiton setting
our $api_key = {}; our $api_key = {};
our $api_key_prefix = {}; our $api_key_prefix = {};
our $api_key_in = {};
# username and password for HTTP basic authentication # username and password for HTTP basic authentication
our $username = ''; our $username = '';
@ -24,4 +25,56 @@ our $password = '';
# access token for OAuth # access token for OAuth
our $access_token = ''; 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; 1;

View File

@ -23,7 +23,7 @@ role.
package main; package main;
my $api = MyApp->new; my $api = MyApp->new({ tokens => $tokens });
my $pet = $api->get_pet_by_id(pet_id => $pet_id); my $pet = $api->get_pet_by_id(pet_id => $pet_id);
@ -46,14 +46,40 @@ For documentation of all these methods, see AUTOMATIC DOCUMENTATION below.
## Configuring authentication ## Configuring authentication
If your Swagger spec does not describe authentication, you can write an In the normal case, the Swagger spec will describe what parameters are
`auth_setup_handler()` method in your base class to handle it (see below). required and where to put them. You just need to supply the tokens.
In the normal case, the Swagger spec will describe what parameters are required my $tokens = {
and where to put them. You just need to supply the authorization 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 });
These should go in the `WWW::{{moduleName}}::Configuration` namespace as follows. Note these are all optional, as are `prefix` and `in`, and depend on the API
Note these are all optional, and depend on the API you are accessing. 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` - `$WWW::{{moduleName}}::Configuration::username`
@ -88,63 +114,19 @@ Note these are all optional, and depend on the API you are accessing.
# METHODS # METHODS
## `auth_setup_handler()` ## `base_url`
This method does not exist! But if you add it to the class that consumes this
role, it will be called to set up authentication.
package MyApp;
use Moose;
with 'WWW::{{moduleName}}::Role';
sub auth_setup_handler {
my ($self, %p) = @_;
$p{header_params}->{'X-TargetApp-apiKey'} = $api_key;
$p{header_params}->{'X-TargetApp-secretKey'} = $secret_key;
}
# somewhere else...
my $api = MyApp->new;
my $pet = $api->get_pet_by_id(pet_id => $pet_id);
So, `auth_setup_handler()` will be called on your `$api` object and passed the
following parameters:
- `header_params`
A hashref that will become the request headers. You can insert auth
parameters.
- `query_params`
A hashref that will be encoded into the request URL. You can insert auth
parameters.
- `auth_settings`
TODO. Probably not necessary?
- `api_client`
A reference to the `WWW::{{moduleName}}::ApiClient` object that is responsible
for communicating with the server. Just in case that's useful.
## base\_url
The generated code has the `base_url` already set as a default value. This method 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 returns (and optionally sets, but only if the API client has not been
created yet) the current value of `base_url`. created yet) the current value of `base_url`.
## api\_factory ## `api_factory`
Returns an API factory object. You probably won't need to call this directly. 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->api_factory('Pet'); # returns a WWW::{{moduleName}}::PetApi instance
$self->pet_api; # the same $self->pet_api; # the same
# MISSING METHODS # MISSING METHODS
@ -202,11 +184,11 @@ Additional documentation for each class and method may be provided by the Swagge
spec. If so, this is available via the `class_documentation()` and spec. If so, this is available via the `class_documentation()` and
`method_documentation()` methods on each generated API and class: `method_documentation()` methods on each generated API and class:
my $cdoc = $api->pet_api->class_documentation; my $cdoc = $api->pet_api->class_documentation;
my $cmdoc = $api->pet_api->method_documentation->{$method_name}; my $cmdoc = $api->pet_api->method_documentation->{$method_name};
my $odoc = $api->get_pet_by_id->(pet_id => $pet_id)->class_documentation; 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}; 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. Each of these calls returns a hashref with various useful pieces of information.

View File

@ -8,19 +8,32 @@ use Log::Any qw($log);
use WWW::{{moduleName}}::ApiFactory; use WWW::{{moduleName}}::ApiFactory;
has base_url => ( is => 'ro', has base_url => ( is => 'ro',
required => 0, required => 0,
isa => 'Str', isa => 'Str',
); );
has api_factory => ( is => 'ro', has api_factory => ( is => 'ro',
isa => 'WWW::{{moduleName}}::ApiFactory', isa => 'WWW::{{moduleName}}::ApiFactory',
builder => '_build_af', builder => '_build_af',
lazy => 1, lazy => 1,
); );
has tokens => ( is => 'ro',
isa => 'HashRef',
required => 0,
default => sub {{=<% %>=}}{{}}<%={{ }}=%>, # !
);
has _cfg => ( is => 'ro',
isa => 'Str',
default => 'WWW::{{moduleName}}::Configuration',
);
sub BUILD { sub BUILD {
my $self = shift; my $self = shift;
$self->_cfg->accept_tokens( $self->tokens ) if keys %{$self->tokens};
# ignore these symbols imported into API namespaces # ignore these symbols imported into API namespaces
my %outsiders = map {$_ => 1} qw( croak ); my %outsiders = map {$_ => 1} qw( croak );
@ -93,7 +106,7 @@ role.
package main; package main;
my $api = MyApp->new; my $api = MyApp->new({ tokens => $tokens });
my $pet = $api->get_pet_by_id(pet_id => $pet_id); my $pet = $api->get_pet_by_id(pet_id => $pet_id);
@ -115,14 +128,40 @@ For documentation of all these methods, see AUTOMATIC DOCUMENTATION below.
=head2 Configuring authentication =head2 Configuring authentication
If your Swagger spec does not describe authentication, you can write an In the normal case, the Swagger spec will describe what parameters are
C<auth_setup_handler()> method in your base class to handle it (see below). required and where to put them. You just need to supply the tokens.
In the normal case, the Swagger spec will describe what parameters are required my $tokens = {
and where to put them. You just need to supply the authorization 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 });
These should go in the C<WWW::{{moduleName}}::Configuration> namespace as follows. Note these are all optional, as are C<prefix> and C<in>, and depend on the API
Note these are all optional, and depend on the API you are accessing. you are accessing. Usually C<prefix> and C<in> will be determined by the code generator from
the spec and you will not need to set them at run time. If not, C<in> will
default to 'head' and C<prefix> to the empty string.
The tokens will be placed in the C<WWW::{{moduleName}}::Configuration> namespace
as follows, but you don't need to know about this.
=over 4 =over 4
@ -161,68 +200,19 @@ String. The OAuth access token.
=head1 METHODS =head1 METHODS
=head2 C<auth_setup_handler()> =head2 C<base_url>
This method does not exist! But if you add it to the class that consumes this
role, it will be called to set up authentication.
package MyApp;
use Moose;
with 'WWW::{{moduleName}}::Role';
sub auth_setup_handler {
my ($self, %p) = @_;
$p{header_params}->{'X-TargetApp-apiKey'} = $api_key;
$p{header_params}->{'X-TargetApp-secretKey'} = $secret_key;
}
# somewhere else...
my $api = MyApp->new;
my $pet = $api->get_pet_by_id(pet_id => $pet_id);
So, C<auth_setup_handler()> will be called on your C<$api> object and passed the
following parameters:
=over 4
=item C<header_params>
A hashref that will become the request headers. You can insert auth
parameters.
=item C<query_params>
A hashref that will be encoded into the request URL. You can insert auth
parameters.
=item C<auth_settings>
TODO. Probably not necessary?
=item C<api_client>
A reference to the C<WWW::{{moduleName}}::ApiClient> object that is responsible
for communicating with the server. Just in case that's useful.
=back
=head2 base_url
The generated code has the C<base_url> already set as a default value. This method The generated code has the C<base_url> already set as a default value. This method
returns (and optionally sets, but only if the API client has not been returns (and optionally sets, but only if the API client has not been
created yet) the current value of C<base_url>. created yet) the current value of C<base_url>.
=head2 api_factory =head2 C<api_factory>
Returns an API factory object. You probably won't need to call this directly. 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->api_factory('Pet'); # returns a WWW::{{moduleName}}::PetApi instance
$self->pet_api; # the same $self->pet_api; # the same
=head1 MISSING METHODS =head1 MISSING METHODS
@ -280,13 +270,13 @@ Additional documentation for each class and method may be provided by the Swagge
spec. If so, this is available via the C<class_documentation()> and spec. If so, this is available via the C<class_documentation()> and
C<method_documentation()> methods on each generated API and class: C<method_documentation()> methods on each generated API and class:
my $cdoc = $api->pet_api->class_documentation; my $cdoc = $api->pet_api->class_documentation;
my $cmdoc = $api->pet_api->method_documentation->{$method_name}; my $cmdoc = $api->pet_api->method_documentation->{$method_name};
my $odoc = $api->get_pet_by_id->(pet_id => $pet_id)->class_documentation; 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}; 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. Each of these calls returns a hashref with various useful pieces of information.
=cut =cut

View File

@ -134,7 +134,7 @@ sub {{nickname}} {
}{{/bodyParams}} }{{/bodyParams}}
# authentication setting, if any # authentication setting, if any
my $auth_settings = [{{#authMethods}}'{{name}}'{{#hasMore}}, {{/hasMore}}{{/authMethods}}]; my $auth_settings = [qw({{#authMethods}}{{name}} {{/authMethods}})];
# make the API Call # make the API Call
{{#returnType}}my $response = $self->{api_client}->call_api($_resource_path, $_method, {{#returnType}}my $response = $self->{api_client}->call_api($_resource_path, $_method,

View File

@ -23,7 +23,7 @@ role.
package main; package main;
my $api = MyApp->new; my $api = MyApp->new({ tokens => $tokens });
my $pet = $api->get_pet_by_id(pet_id => $pet_id); my $pet = $api->get_pet_by_id(pet_id => $pet_id);
@ -46,14 +46,40 @@ For documentation of all these methods, see AUTOMATIC DOCUMENTATION below.
## Configuring authentication ## Configuring authentication
If your Swagger spec does not describe authentication, you can write an In the normal case, the Swagger spec will describe what parameters are
`auth_setup_handler()` method in your base class to handle it (see below). required and where to put them. You just need to supply the tokens.
In the normal case, the Swagger spec will describe what parameters are required my $tokens = {
and where to put them. You just need to supply the authorization 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 });
These should go in the `WWW::SwaggerClient::Configuration` namespace as follows. Note these are all optional, as are `prefix` and `in`, and depend on the API
Note these are all optional, and depend on the API you are accessing. 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::SwaggerClient::Configuration` namespace
as follows, but you don't need to know about this.
- `$WWW::SwaggerClient::Configuration::username` - `$WWW::SwaggerClient::Configuration::username`
@ -88,63 +114,19 @@ Note these are all optional, and depend on the API you are accessing.
# METHODS # METHODS
## `auth_setup_handler()` ## `base_url`
This method does not exist! But if you add it to the class that consumes this
role, it will be called to set up authentication.
package MyApp;
use Moose;
with 'WWW::SwaggerClient::Role';
sub auth_setup_handler {
my ($self, %p) = @_;
$p{header_params}->{'X-TargetApp-apiKey'} = $api_key;
$p{header_params}->{'X-TargetApp-secretKey'} = $secret_key;
}
# somewhere else...
my $api = MyApp->new;
my $pet = $api->get_pet_by_id(pet_id => $pet_id);
So, `auth_setup_handler()` will be called on your `$api` object and passed the
following parameters:
- `header_params`
A hashref that will become the request headers. You can insert auth
parameters.
- `query_params`
A hashref that will be encoded into the request URL. You can insert auth
parameters.
- `auth_settings`
TODO. Probably not necessary?
- `api_client`
A reference to the `WWW::SwaggerClient::ApiClient` object that is responsible
for communicating with the server. Just in case that's useful.
## base\_url
The generated code has the `base_url` already set as a default value. This method 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 returns (and optionally sets, but only if the API client has not been
created yet) the current value of `base_url`. created yet) the current value of `base_url`.
## api\_factory ## `api_factory`
Returns an API factory object. You probably won't need to call this directly. 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->api_factory('Pet'); # returns a WWW::SwaggerClient::PetApi instance
$self->pet_api; # the same $self->pet_api; # the same
# MISSING METHODS # MISSING METHODS
@ -202,11 +184,11 @@ Additional documentation for each class and method may be provided by the Swagge
spec. If so, this is available via the `class_documentation()` and spec. If so, this is available via the `class_documentation()` and
`method_documentation()` methods on each generated API and class: `method_documentation()` methods on each generated API and class:
my $cdoc = $api->pet_api->class_documentation; my $cdoc = $api->pet_api->class_documentation;
my $cmdoc = $api->pet_api->method_documentation->{$method_name}; my $cmdoc = $api->pet_api->method_documentation->{$method_name};
my $odoc = $api->get_pet_by_id->(pet_id => $pet_id)->class_documentation; 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}; 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. Each of these calls returns a hashref with various useful pieces of information.

View File

@ -34,6 +34,8 @@ sub _new_instance
return bless \%args, $class; return bless \%args, $class;
} }
sub _cfg {'WWW::SwaggerClient::Configuration'}
# Set the user agent of the API client # Set the user agent of the API client
# #
# @param string $user_agent The user agent of the API client # @param string $user_agent The user agent of the API client
@ -308,18 +310,8 @@ sub get_api_key_with_prefix
sub update_params_for_auth { sub update_params_for_auth {
my ($self, $header_params, $query_params, $auth_settings) = @_; my ($self, $header_params, $query_params, $auth_settings) = @_;
# we can defer to the application if the spec doesn't describe authentication return $self->_global_auth_setup($header_params, $query_params)
if ($self->{auth_setup_handler_object}) { unless $auth_settings && @$auth_settings;
$self->{auth_setup_handler_object}->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);
# one endpoint can have more than 1 auth settings # one endpoint can have more than 1 auth settings
foreach my $auth (@$auth_settings) { foreach my $auth (@$auth_settings) {
@ -336,10 +328,47 @@ sub update_params_for_auth {
} }
else { 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; 1;

View File

@ -16,6 +16,7 @@ our $http_user_agent = 'Perl-Swagger';
# authenticaiton setting # authenticaiton setting
our $api_key = {}; our $api_key = {};
our $api_key_prefix = {}; our $api_key_prefix = {};
our $api_key_in = {};
# username and password for HTTP basic authentication # username and password for HTTP basic authentication
our $username = ''; our $username = '';
@ -24,4 +25,56 @@ our $password = '';
# access token for OAuth # access token for OAuth
our $access_token = ''; 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; 1;

View File

@ -106,7 +106,7 @@ sub update_pet {
} }
# authentication setting, if any # authentication setting, if any
my $auth_settings = ['petstore_auth']; my $auth_settings = [qw(petstore_auth )];
# make the API Call # make the API Call
@ -170,7 +170,7 @@ sub add_pet {
} }
# authentication setting, if any # authentication setting, if any
my $auth_settings = ['petstore_auth']; my $auth_settings = [qw(petstore_auth )];
# make the API Call # make the API Call
@ -234,7 +234,7 @@ sub find_pets_by_status {
# authentication setting, if any # authentication setting, if any
my $auth_settings = ['petstore_auth']; my $auth_settings = [qw(petstore_auth )];
# make the API Call # make the API Call
my $response = $self->{api_client}->call_api($_resource_path, $_method, my $response = $self->{api_client}->call_api($_resource_path, $_method,
@ -301,7 +301,7 @@ sub find_pets_by_tags {
# authentication setting, if any # authentication setting, if any
my $auth_settings = ['petstore_auth']; my $auth_settings = [qw(petstore_auth )];
# make the API Call # make the API Call
my $response = $self->{api_client}->call_api($_resource_path, $_method, my $response = $self->{api_client}->call_api($_resource_path, $_method,
@ -375,7 +375,7 @@ sub get_pet_by_id {
# authentication setting, if any # authentication setting, if any
my $auth_settings = ['api_key']; my $auth_settings = [qw(api_key )];
# make the API Call # make the API Call
my $response = $self->{api_client}->call_api($_resource_path, $_method, my $response = $self->{api_client}->call_api($_resource_path, $_method,
@ -471,7 +471,7 @@ sub update_pet_with_form {
# authentication setting, if any # authentication setting, if any
my $auth_settings = ['petstore_auth']; my $auth_settings = [qw(petstore_auth )];
# make the API Call # make the API Call
@ -551,7 +551,7 @@ sub delete_pet {
# authentication setting, if any # authentication setting, if any
my $auth_settings = ['petstore_auth']; my $auth_settings = [qw(petstore_auth )];
# make the API Call # make the API Call
@ -645,7 +645,7 @@ sub upload_file {
# authentication setting, if any # authentication setting, if any
my $auth_settings = ['petstore_auth']; my $auth_settings = [qw(petstore_auth )];
# make the API Call # make the API Call

View File

@ -8,19 +8,32 @@ use Log::Any qw($log);
use WWW::SwaggerClient::ApiFactory; use WWW::SwaggerClient::ApiFactory;
has base_url => ( is => 'ro', has base_url => ( is => 'ro',
required => 0, required => 0,
isa => 'Str', isa => 'Str',
); );
has api_factory => ( is => 'ro', has api_factory => ( is => 'ro',
isa => 'WWW::SwaggerClient::ApiFactory', isa => 'WWW::SwaggerClient::ApiFactory',
builder => '_build_af', builder => '_build_af',
lazy => 1, lazy => 1,
); );
has tokens => ( is => 'ro',
isa => 'HashRef',
required => 0,
default => sub {{}}, # !
);
has _cfg => ( is => 'ro',
isa => 'Str',
default => 'WWW::SwaggerClient::Configuration',
);
sub BUILD { sub BUILD {
my $self = shift; my $self = shift;
$self->_cfg->accept_tokens( $self->tokens ) if keys %{$self->tokens};
# ignore these symbols imported into API namespaces # ignore these symbols imported into API namespaces
my %outsiders = map {$_ => 1} qw( croak ); my %outsiders = map {$_ => 1} qw( croak );
@ -93,7 +106,7 @@ role.
package main; package main;
my $api = MyApp->new; my $api = MyApp->new({ tokens => $tokens });
my $pet = $api->get_pet_by_id(pet_id => $pet_id); my $pet = $api->get_pet_by_id(pet_id => $pet_id);
@ -115,14 +128,40 @@ For documentation of all these methods, see AUTOMATIC DOCUMENTATION below.
=head2 Configuring authentication =head2 Configuring authentication
If your Swagger spec does not describe authentication, you can write an In the normal case, the Swagger spec will describe what parameters are
C<auth_setup_handler()> method in your base class to handle it (see below). required and where to put them. You just need to supply the tokens.
In the normal case, the Swagger spec will describe what parameters are required my $tokens = {
and where to put them. You just need to supply the authorization 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 });
These should go in the C<WWW::SwaggerClient::Configuration> namespace as follows. Note these are all optional, as are C<prefix> and C<in>, and depend on the API
Note these are all optional, and depend on the API you are accessing. you are accessing. Usually C<prefix> and C<in> will be determined by the code generator from
the spec and you will not need to set them at run time. If not, C<in> will
default to 'head' and C<prefix> to the empty string.
The tokens will be placed in the C<WWW::SwaggerClient::Configuration> namespace
as follows, but you don't need to know about this.
=over 4 =over 4
@ -161,68 +200,19 @@ String. The OAuth access token.
=head1 METHODS =head1 METHODS
=head2 C<auth_setup_handler()> =head2 C<base_url>
This method does not exist! But if you add it to the class that consumes this
role, it will be called to set up authentication.
package MyApp;
use Moose;
with 'WWW::SwaggerClient::Role';
sub auth_setup_handler {
my ($self, %p) = @_;
$p{header_params}->{'X-TargetApp-apiKey'} = $api_key;
$p{header_params}->{'X-TargetApp-secretKey'} = $secret_key;
}
# somewhere else...
my $api = MyApp->new;
my $pet = $api->get_pet_by_id(pet_id => $pet_id);
So, C<auth_setup_handler()> will be called on your C<$api> object and passed the
following parameters:
=over 4
=item C<header_params>
A hashref that will become the request headers. You can insert auth
parameters.
=item C<query_params>
A hashref that will be encoded into the request URL. You can insert auth
parameters.
=item C<auth_settings>
TODO. Probably not necessary?
=item C<api_client>
A reference to the C<WWW::SwaggerClient::ApiClient> object that is responsible
for communicating with the server. Just in case that's useful.
=back
=head2 base_url
The generated code has the C<base_url> already set as a default value. This method The generated code has the C<base_url> already set as a default value. This method
returns (and optionally sets, but only if the API client has not been returns (and optionally sets, but only if the API client has not been
created yet) the current value of C<base_url>. created yet) the current value of C<base_url>.
=head2 api_factory =head2 C<api_factory>
Returns an API factory object. You probably won't need to call this directly. 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->api_factory('Pet'); # returns a WWW::SwaggerClient::PetApi instance
$self->pet_api; # the same $self->pet_api; # the same
=head1 MISSING METHODS =head1 MISSING METHODS
@ -280,13 +270,13 @@ Additional documentation for each class and method may be provided by the Swagge
spec. If so, this is available via the C<class_documentation()> and spec. If so, this is available via the C<class_documentation()> and
C<method_documentation()> methods on each generated API and class: C<method_documentation()> methods on each generated API and class:
my $cdoc = $api->pet_api->class_documentation; my $cdoc = $api->pet_api->class_documentation;
my $cmdoc = $api->pet_api->method_documentation->{$method_name}; my $cmdoc = $api->pet_api->method_documentation->{$method_name};
my $odoc = $api->get_pet_by_id->(pet_id => $pet_id)->class_documentation; 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}; 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. Each of these calls returns a hashref with various useful pieces of information.
=cut =cut

View File

@ -97,7 +97,7 @@ sub get_inventory {
# authentication setting, if any # authentication setting, if any
my $auth_settings = ['api_key']; my $auth_settings = [qw(api_key )];
# make the API Call # make the API Call
my $response = $self->{api_client}->call_api($_resource_path, $_method, my $response = $self->{api_client}->call_api($_resource_path, $_method,
@ -164,7 +164,7 @@ sub place_order {
} }
# authentication setting, if any # authentication setting, if any
my $auth_settings = []; my $auth_settings = [qw()];
# make the API Call # make the API Call
my $response = $self->{api_client}->call_api($_resource_path, $_method, my $response = $self->{api_client}->call_api($_resource_path, $_method,
@ -238,7 +238,7 @@ sub get_order_by_id {
# authentication setting, if any # authentication setting, if any
my $auth_settings = []; my $auth_settings = [qw()];
# make the API Call # make the API Call
my $response = $self->{api_client}->call_api($_resource_path, $_method, my $response = $self->{api_client}->call_api($_resource_path, $_method,
@ -312,7 +312,7 @@ sub delete_order {
# authentication setting, if any # authentication setting, if any
my $auth_settings = []; my $auth_settings = [qw()];
# make the API Call # make the API Call

View File

@ -106,7 +106,7 @@ sub create_user {
} }
# authentication setting, if any # authentication setting, if any
my $auth_settings = []; my $auth_settings = [qw()];
# make the API Call # make the API Call
@ -170,7 +170,7 @@ sub create_users_with_array_input {
} }
# authentication setting, if any # authentication setting, if any
my $auth_settings = []; my $auth_settings = [qw()];
# make the API Call # make the API Call
@ -234,7 +234,7 @@ sub create_users_with_list_input {
} }
# authentication setting, if any # authentication setting, if any
my $auth_settings = []; my $auth_settings = [qw()];
# make the API Call # make the API Call
@ -307,7 +307,7 @@ sub login_user {
# authentication setting, if any # authentication setting, if any
my $auth_settings = []; my $auth_settings = [qw()];
# make the API Call # make the API Call
my $response = $self->{api_client}->call_api($_resource_path, $_method, my $response = $self->{api_client}->call_api($_resource_path, $_method,
@ -365,7 +365,7 @@ sub logout_user {
# authentication setting, if any # authentication setting, if any
my $auth_settings = []; my $auth_settings = [qw()];
# make the API Call # make the API Call
@ -436,7 +436,7 @@ sub get_user_by_name {
# authentication setting, if any # authentication setting, if any
my $auth_settings = []; my $auth_settings = [qw()];
# make the API Call # make the API Call
my $response = $self->{api_client}->call_api($_resource_path, $_method, my $response = $self->{api_client}->call_api($_resource_path, $_method,
@ -519,7 +519,7 @@ sub update_user {
} }
# authentication setting, if any # authentication setting, if any
my $auth_settings = []; my $auth_settings = [qw()];
# make the API Call # make the API Call
@ -590,7 +590,7 @@ sub delete_user {
# authentication setting, if any # authentication setting, if any
my $auth_settings = []; my $auth_settings = [qw()];
# make the API Call # make the API Call

View File

@ -1,4 +1,4 @@
use Test::More tests => 21; use Test::More tests => 29;
use Test::Exception; use Test::Exception;
use Test::Warnings 'warnings'; use Test::Warnings 'warnings';
use Test::Deep; use Test::Deep;
@ -15,7 +15,7 @@ SKIP: {
sub auth_setup_handler {} sub auth_setup_handler {}
"; ";
skip 'Moose not installed', 21 if $@; skip 'Moose not installed', 29 if $@;
my $api; my $api;
@ -76,5 +76,65 @@ my $pet_class_doco = { 'description' => '' };
is_deeply($get_pet->class_documentation, $pet_class_doco, 'Pet object class_documentation is available'); is_deeply($get_pet->class_documentation, $pet_class_doco, 'Pet object class_documentation is available');
# / documentation tests # / 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 } # / SKIP