Cloudflare-API
view release on metacpan or search on metacpan
lib/Cloudflare/API.pm view on Meta::CPAN
#
# This file is part of Cloudflare::API.
#
# This software is copyright (c) 2026 by Andrew Speer <andrew.speer@isolutions.com.au>.
#
# This is free software; you can redistribute it and/or modify it under
# the same terms as the Perl 5 programming language system itself.
#
# Full license text is available at:
#
# <http://dev.perl.org/licenses/>
#
package Cloudflare::API;
# Compiler Pragma
#
use strict qw(vars);
use vars qw($VERSION);
use warnings;
# External modules
#
use HTTP::API::Core 1.08;
# Cloudflare::API modules
#
use Cloudflare::API::Error;
# Version information
#
$VERSION='1.011';
# All done. Positive return
#
1;
#============================================================================
sub new {
# Resolve credentials and account context from options or environment
#
my ($class, %opt)=@_;
my $token=exists($opt{'token'}) ? delete($opt{'token'}) : $ENV{'CLOUDFLARE_API_TOKEN'};
die "token is required\n" unless defined($token)&&!ref($token)&&length($token);
my $account_id=exists($opt{'account_id'})
? delete($opt{'account_id'}) : $ENV{'CLOUDFLARE_ACCOUNT_ID'};
die "account_id must be a non-empty scalar\n"
if defined($account_id)&&(ref($account_id)||!length($account_id));
my $base_url=exists($opt{'base_url'})
? delete($opt{'base_url'}) : 'https://api.cloudflare.com/client/v4';
die "base_url must be an HTTPS URL\n"
unless defined($base_url)&&$base_url=~m{\Ahttps://[^/]+(?:/.*)?\z};
# Build the HTTP client with bearer authentication
#
my %core_opt=(
base_url => $base_url,
headers => { Authorization => "Bearer $token", Accept => 'application/json' },
retry => { attempts => 1 }
);
foreach my $name (qw(timeout transport retry hooks)) {
$core_opt{$name}=delete($opt{$name}) if exists($opt{$name});
}
die "unknown constructor option: $_\n" foreach sort(keys(%opt));
# Retain the account ID for resource methods
#
my $self=bless({
account_id => $account_id,
core_or => HTTP::API::Core->new(%core_opt)
}, $class);
return $self;
}
sub account_id { return $_[0]->{'account_id'} }
sub response {
# Require a relative API path so credentials stay on the configured host
#
my ($self, $method, $path, %opt)=@_;
die "path must begin with one slash\n"
unless defined($path)&&!ref($path)&&$path=~m{\A/(?!/)};
return $self->{'core_or'}->request($method, $path, %opt);
}
sub raw_request {
my $self=shift();
return $self->response(@_);
}
sub request {
# Unwrap result by default, but allow the full decoded envelope
#
my ($self, $method, $path, %opt)=@_;
my $full_response=delete($opt{'full_response'});
my $body_hr=$self->request_full($method, $path, %opt);
return $full_response ? $body_hr : $body_hr->{'result'};
}
sub request_full {
# Parse the Cloudflare envelope and surface reported API failures
#
my ($self, $method, $path, %opt)=@_;
my $response_or=$self->response($method, $path, %opt);
return $self->decode_response($response_or);
}
sub decode_response {
# Decode and validate the Cloudflare response shared by direct requests
# and paginated extractors
#
my ($self, $response_or, $body_hr)=@_;
return { success => 1, result => undef } unless $response_or->has_content();
$body_hr=$response_or->json() unless defined($body_hr);
die "Cloudflare returned a non-object JSON response\n" unless ref($body_hr) eq 'HASH';
if (exists($body_hr->{'success'})&&!$body_hr->{'success'}) {
die Cloudflare::API::Error->new(
response => $response_or,
errors => $body_hr->{'errors'},
messages => $body_hr->{'messages'}
);
}
lib/Cloudflare/API.pm view on Meta::CPAN
sub kv { require Cloudflare::API::KV; return Cloudflare::API::KV->new($_[0]) }
sub d1 { require Cloudflare::API::D1; return Cloudflare::API::D1->new($_[0]) }
sub queues { require Cloudflare::API::Queues; return Cloudflare::API::Queues->new($_[0]) }
sub hyperdrive { require Cloudflare::API::Hyperdrive; return Cloudflare::API::Hyperdrive->new($_[0]) }
sub secrets_store { require Cloudflare::API::SecretsStore; return Cloudflare::API::SecretsStore->new($_[0]) }
sub accounts { require Cloudflare::API::Accounts; return Cloudflare::API::Accounts->new($_[0]) }
sub zones { require Cloudflare::API::Zones; return Cloudflare::API::Zones->new($_[0]) }
__END__
=begin markdown
# Cloudflare::API #
# NAME #
Cloudflare::API - Perl client for Cloudflare resource management
# SYNOPSIS #
```perl
use Cloudflare::API;
my $api=Cloudflare::API->new(
token => $ENV{'CLOUDFLARE_API_TOKEN'},
account_id => $ENV{'CLOUDFLARE_ACCOUNT_ID'}
);
my $buckets_ar=$api->r2()->list_buckets();
my $page_or=$api->r2()->list_buckets_page(per_page => 100);
my $page_hr=$api->r2()->list_buckets_page_response(per_page => 100);
my $response_or=$api->response('GET', '/accounts');
my $zone=$api->zones()->get($zone_id);
```
# DESCRIPTION #
`Cloudflare::API` supplies a bearer-authenticated HTTP client and accessors for the resource modules below. It requires Perl 5.10 or later, HTTP::API::Core 1.08 or later, and HTTPS support through IO::Socket::SSL. Resource objects share the same clie...
An API token is required. Supply `token` to `new()` or set `CLOUDFLARE_API_TOKEN`. Account-scoped methods also need `account_id` or `CLOUDFLARE_ACCOUNT_ID`; account and zone lookups work without a default account ID. Use a token with the permissions ...
# RESOURCE MODULES #
Each accessor creates a resource object. Consult its own man page for arguments, return values, and service-specific limits.
* **[Cloudflare::API::Accounts](API/Accounts.pm.md)** (`accounts()`) lists and retrieves accounts visible to the token.
* **[Cloudflare::API::Zones](API/Zones.pm.md)** (`zones()`) lists and retrieves zones.
* **[Cloudflare::API::Workers](API/Workers.pm.md)** (`workers()`) manages scripts, versions, assets, deployments, secrets, subdomains, and zone routes.
* **[Cloudflare::API::R2](API/R2.pm.md)** (`r2()`) manages R2 buckets.
* **[Cloudflare::API::KV](API/KV.pm.md)** (`kv()`) manages Workers KV namespaces, keys, and raw values.
* **[Cloudflare::API::D1](API/D1.pm.md)** (`d1()`) manages D1 databases and runs REST SQL queries.
* **[Cloudflare::API::Queues](API/Queues.pm.md)** (`queues()`) manages queues and consumers.
* **[Cloudflare::API::Hyperdrive](API/Hyperdrive.pm.md)** (`hyperdrive()`) manages database connection configurations.
* **[Cloudflare::API::SecretsStore](API/SecretsStore.pm.md)** (`secrets_store()`) manages stores and write-only secrets.
* **[Cloudflare::API::Error](API/Error.pm.md)** represents a Cloudflare JSON response reporting failure despite HTTP success.
* **[Cloudflare::API::Resource](API/Resource.pm.md)** is the shared base class for resource objects; applications normally use the accessors above rather than constructing it.
# METHODS #
* **new(%options)**
Construct the client. `token` is a non-empty scalar and is mandatory after environment fallback. `account_id` is an optional non-empty scalar. `base_url` defaults to `https://api.cloudflare.com/client/v4` and must be an HTTPS URL. `timeout`, `ret...
* **account_id()**
Return the configured account ID, or `undef` if none was supplied.
* **workers(), r2(), kv(), d1(), queues(), hyperdrive(), secrets_store(), accounts(), zones()**
Return a new object of the corresponding resource class, retaining this client. Resource modules are loaded when their accessor is called.
* **request($method, $path, %options)**
Call a JSON endpoint and return the decoded Cloudflare response's `result`, which may be a hash reference, array reference, scalar, or `undef` according to the endpoint. `full_response => 1` returns the complete decoded response hash instead. Oth...
* **request_full($method, $path, %options)**
Return the complete decoded Cloudflare JSON hash reference, including fields such as `success`, `errors`, `messages`, and `result_info` when Cloudflare supplies them. An empty successful body yields `{ success => 1, result => undef }`. A non-obje...
* **response($method, $path, %options)**
Return an `HTTP::API::Core::Response` object without decoding the body. Use this for non-JSON responses. It enforces the same single-slash relative-path rule as `request()`.
* **raw_request($method, $path, %options)**
Compatibility alias for `response()`.
* **account_path(@segments)**
Return `/accounts/<configured ID>/...` with each component percent-encoded. It throws if no account ID was configured. Resource modules use this helper; callers using `response()` can use it to build account-scoped paths.
* **segment($value)**
Return a non-empty scalar as one percent-encoded UTF-8 URL path component. It rejects references, empty strings, and undefined values. Encode dynamic components when building low-level paths yourself.
# RETURN VALUES AND ERRORS #
Named non-list resource methods normally return the JSON `result`; pass `full_response => 1` to retain the complete decoded Cloudflare response. List methods automatically follow every page reported by Cloudflare and return a flat array reference con...
Every list method has two additional forms. Its `_page()` form returns a lazy `HTTP::API::Core::Pagination` object whose `next()` method yields one item and fetches subsequent pages as needed; `all()` collects its remaining items. Its `_page_response...
List filters are named arguments sent as query parameters. Exceptions from HTTP or transport failures remain `HTTP::API::Core::Error` objects; their decoded Cloudflare body is available through `json()`. A successful HTTP status with `success: false`...
# SEE ALSO #
[Cloudflare API documentation](https://developers.cloudflare.com/api/), HTTP::API::Core, the resource module man pages above, and the `cloudflare-api` command.
# AUTHOR #
Andrew Speer <andrew.speer@isolutions.com.au>
# LICENSE and COPYRIGHT
This file is part of Cloudflare::API.
This software is copyright (c) 2026 by Andrew Speer <andrew.speer@isolutions.com.au>.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
Full license text is available at:
lib/Cloudflare/API.pm view on Meta::CPAN
B<L<Cloudflare::API::Zones|Cloudflare::API::Zones>> (C<zones()>) lists and retrieves zones.
=item *
B<L<Cloudflare::API::Workers|Cloudflare::API::Workers>> (C<workers()>) manages scripts, versions, assets, deployments, secrets, subdomains, and zone routes.
=item *
B<L<Cloudflare::API::R2|Cloudflare::API::R2>> (C<r2()>) manages R2 buckets.
=item *
B<L<Cloudflare::API::KV|Cloudflare::API::KV>> (C<kv()>) manages Workers KV namespaces, keys, and raw values.
=item *
B<L<Cloudflare::API::D1|Cloudflare::API::D1>> (C<d1()>) manages D1 databases and runs REST SQL queries.
=item *
B<L<Cloudflare::API::Queues|Cloudflare::API::Queues>> (C<queues()>) manages queues and consumers.
=item *
B<L<Cloudflare::API::Hyperdrive|Cloudflare::API::Hyperdrive>> (C<hyperdrive()>) manages database connection configurations.
=item *
B<L<Cloudflare::API::SecretsStore|Cloudflare::API::SecretsStore>> (C<secrets_store()>) manages stores and write-only secrets.
=item *
B<L<Cloudflare::API::Error|Cloudflare::API::Error>> represents a Cloudflare JSON response reporting failure despite HTTP success.
=item *
B<L<Cloudflare::API::Resource|Cloudflare::API::Resource>> is the shared base class for resource objects; applications normally use the accessors above rather than constructing it.
=back
=head1 METHODS
=over
=item *
B<new(%options)>
Construct the client. C<token> is a non-empty scalar and is mandatory after environment fallback. C<account_id> is an optional non-empty scalar. C<base_url> defaults to C<https://api.cloudflare.com/client/v4> and must be an HTTPS URL. C<timeout>, C<r...
=item *
B<account_id()>
Return the configured account ID, or C<undef> if none was supplied.
=item *
B<workers(), r2(), kv(), d1(), queues(), hyperdrive(), secrets_store(), accounts(), zones()>
Return a new object of the corresponding resource class, retaining this client. Resource modules are loaded when their accessor is called.
=item *
B<request($method, $path, %options)>
Call a JSON endpoint and return the decoded Cloudflare response's C<result>, which may be a hash reference, array reference, scalar, or C<undef> according to the endpoint. C<<< full_response => 1 >>> returns the complete decoded response hash instead...
=item *
B<request_full($method, $path, %options)>
Return the complete decoded Cloudflare JSON hash reference, including fields such as C<success>, C<errors>, C<messages>, and C<result_info> when Cloudflare supplies them. An empty successful body yields C<<< { success => 1, result => undef } >>>. A n...
=item *
B<response($method, $path, %options)>
Return an C<HTTP::API::Core::Response> object without decoding the body. Use this for non-JSON responses. It enforces the same single-slash relative-path rule as C<request()>.
=item *
B<raw_request($method, $path, %options)>
Compatibility alias for C<response()>.
=item *
B<account_path(@segments)>
Return C<<< /accounts/<configured ID>/... >>> with each component percent-encoded. It throws if no account ID was configured. Resource modules use this helper; callers using C<response()> can use it to build account-scoped paths.
=item *
( run in 0.884 second using v1.01-cache-2.11-cpan-3f962061493 )