package WebService::ForecastIo;
use Moose;
use MooseX::Types::URI 'Uri';
use MooseX::Types::DateTime;
use MooseX::Params::Validate;
use Moose::Util::TypeConstraints;
use DateTime::Format::ISO8601;
use WebService::ForecastIo::Response;
has base_uri => (
is => 'ro',
isa => Uri,
coerce => 1,
default => 'https://api.forecast.io/forecast',
);
has api_key => (
is => 'ro',
isa => 'Str',
required => 1,
);
has user_agent => (
is => 'ro',
isa => duck_type(['get']),
lazy_build => 1,
);
sub _build_user_agent {
require LWP::UserAgent;
my $agent = LWP::UserAgent->new(
agent => __PACKAGE__ . ' version ' . ($WebService::ForecastIo::VERSION // 'devel' ),
env_proxy => 1,
keep_alive => 1,
);
$agent->default_header( 'Accept-Encoding' => 'gzip' );
return $agent;
}
sub _make_request_uri {
my ($self,%opts) = @_;
my ($lat,$lon,$time) = delete @opts{qw(latitude longitude time)};
my $req_uri = $self->base_uri->clone;
my $time_str;
if ($time) {
$time_str = $time->iso8601;
my $tz = $time->time_zone;
if ($tz->is_utc) { $time_str .= 'Z' }
elsif (not $tz->is_floating) {
$time_str .= DateTime::TimeZone->offset_as_string(
$tz->offset_for_datetime($time)
);
}
}
$req_uri->path_segments(
grep { length($_) }
$req_uri->path_segments,
$self->api_key,
"$lat,$lon",
$time_str,
);
if ($opts{exclude}) {
$opts{exclude} = join ',',@{$opts{exclude}};
}
$req_uri->query_form(\%opts);
return $req_uri;
}
enum my $units_type=__PACKAGE__.'::units',
[qw(us si ca uk auto)];
enum my $block_type=__PACKAGE__.'::block',
[qw(currently minutely hourly daily alerts flags)];
coerce 'DateTime', from 'Str',
via {
s{([+-])(\d\d)(\d\d)\z}{$1$2:$3};
DateTime::Format::ISO8601->new->parse_datetime($_)
};
sub request {
my ($self,%opts) = validated_hash(
\@_,
latitude => { isa => 'Num' },
longitude => { isa => 'Num' },
time => { isa => 'DateTime', optional => 1, coerce => 1 },
units => { isa => $units_type, default => 'si' },
exclude => { isa => "ArrayRef[$block_type]", default => sub { [] } },
);
my $uri = $self->_make_request_uri(%opts);
my $response = $self->user_agent->get($uri);
if ($response->is_success) {
return WebService::ForecastIo::Response->new(
$response->decoded_content,
);
}
else {
die $response->status_line
}
}
1;