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) { my $json = $response->decoded_content; my $res = WebService::ForecastIo::Response->new($json); return wantarray ? ($res,$json) : $res } else { die $response->status_line } } 1;