package WebService::ForecastIo; use Moo; use 5.10.0; use Types::Standard -types,'slurpy'; use Types::URI 'Uri'; use Types::DateTime -all; use Type::Params; use Future::AsyncAwait; use WebService::ForecastIo::Response; use DateTime::TimeZone; use namespace::clean; has base_uri => ( is => 'ro', isa => Uri, default => 'https://api.pirateweather.net/forecast', coerce => Uri->coercion, ); has api_key => ( is => 'ro', isa => Str, required => 1, ); has user_agent => ( is => 'ro', isa => HasMethods['do_request'], required => 1, ); 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; } my $units_type = Enum [qw(us si ca uk auto)]; my $block_type = Enum [qw(currently minutely hourly daily alerts flags sources)]; async sub request { state $argcheck = compile( Object, Dict[ latitude => Num, longitude => Num, time => Optional[DateTimeUTC], units => Optional[$units_type], exclude => Optional[ArrayRef[$block_type]], ], ); my ($self,$opts) = $argcheck->(@_); $opts->{units} //= 'si'; $opts->{exclude} //= []; my $uri = $self->_make_request_uri({%$opts}); my $response = await $self->user_agent->do_request(uri => $uri); if ($response->is_success) { my $json = $response->decoded_content; return WebService::ForecastIo::Response->new($json); } else { die $response->status_line; } } 1;