App-Presto
view release on metacpan
or search on metacpan
README
view on Meta::CPAN
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | opposite end of the spectrum) just using curl directly on the
command-line. This tool attempts to find some sort of middle ground by
providing a quasi-DSL for interacting with a RESTful service in an
interactive way.
FEATURES
Basic HTTP methods
All HTTP methods are implemented as commands in presto. The URL that is
given is appended to the endpoint specified when presto is invoked as
shown in the SYNOPSIS above.
Request Building
If the endpoint contains a * character the URL fragment specified in
the GET/POST/etc command is inserted at that point. This allows you to
do things like auto-append a file extension to all URLs. For instance:
bash$ presto http:// my -server.com*.json
http:// my -server.com> GET /product/1
In this case, the full URL would be
http:// my -server.com/product/1.json. If no * is found in the URL, the
URL fragment is simply appended at the end of the endpoint.
All arguments after the first will be treated as query parameters ( for
GET/HEAD/DELETE requests) or request content ( for POST/PUT requests).
For instance:
http:// my -server.com> GET /products limit=10 offset=20
http:// my -server.com> POST /products '{"name":"A New Product"}'
|
README
view on Meta::CPAN
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | like the -B file-test operator), the output is not printed to STDOUT.
Instead, you may want to use output redirection as show above and send the response body to a file.
http:// my -server.com> GET /some-image.jpg >foo.jpg
Persistent Configuration
As demonstrated above, you can use the config command to change the behavior of presto. These configuration options are persisted in a
config file specific to the endpoint provided at the command-line and
will be reloaded the next time you invoke presto with the same
endpoint.
Current valid config keys are:
* verbose
Boolean, when enabled, dumps request/response to STDOUT (defaults to
"0" )
* deserialize_response
|
README
view on Meta::CPAN
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | * pretty_printer
Must be one of the supported modules (i.e. Data::Dumper or JSON). Use
tab completion to see currently supported values (defaults to
"JSON" ).
* binmode
Used to set encoding of STDIN and STDOUT handles (defaults to "utf8" )
TODO: provide a means for aliasing endpoints so that configuration is
shared across multiple endpoints.
History and Scripting
Just like configuration, command history is maintained separately for
each endpoint specified on the command-line and is persisted across
sessions (assuming you have a capable Term::Readline library
installed). You can interrogate the history using the (surprisingly
named) history command. It supports a small subset of the bash history
command:
http:// my -server.com> history
http:// my -server.com> history 5
|
README.mkdn
view on Meta::CPAN
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | answers typically point to some horrible GUI or (on the complete opposite
end of the spectrum) just using `curl` directly on the command-line.
This tool attempts to find some sort of middle ground by providing a
quasi-DSL for interacting with a RESTful service in an interactive way.
All HTTP methods are implemented as commands in presto. The URL that is
given is appended to the endpoint specified when presto is invoked as
shown in the SYNOPSIS above.
If the endpoint contains a `*` character the URL fragment specified in
the GET/POST/etc command is inserted at that point. This allows you to
do things like auto-append a file extension to all URLs. For instance:
bash$ presto http:// my -server.com*.json
http:// my -server.com> GET /product/1
In this case, the full URL would be
`http:// my -server.com/product/1.json`. If no `*` is found in the URL,
the URL fragment is simply appended at the end of the endpoint.
All arguments after the first will be treated as query parameters ( for
GET/HEAD/DELETE requests) or request content ( for POST/PUT requests). For
instance:
http:// my -server.com> GET /products limit=10 offset=20
http:// my -server.com> POST /products '{"name":"A New Product"}'
|
README.mkdn
view on Meta::CPAN
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | like the `-B` file-test operator), the output is not printed to STDOUT.
Instead, you may want to use output redirection as show above and send the response body to a file.
http:// my -server.com> GET /some-image.jpg >foo.jpg
As demonstrated above, you can use the `config` command to change the behavior of presto. These configuration options are persisted in a
config file specific to the endpoint provided at the command-line and
will be reloaded the next time you invoke presto with the same endpoint.
Current valid config keys are:
- verbose
Boolean, when enabled, dumps request/response to STDOUT (defaults to "0" )
- deserialize\_response
Boolean, when enabled response body is parsed based on the `Content-Type`
|
README.mkdn
view on Meta::CPAN
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | - pretty\_printer
Must be one of the supported modules (i.e. Data::Dumper or JSON).
Use tab completion to see currently supported values (defaults to "JSON" ).
- binmode
Used to set encoding of STDIN and STDOUT handles (defaults to "utf8" )
* *TODO :** provide a means for aliasing endpoints so that configuration
is shared across multiple endpoints.
Just like configuration, command history is maintained separately for each
endpoint specified on the command-line and is persisted across sessions
(assuming you have a capable Term::Readline library installed). You can
interrogate the history using the (surprisingly named) `history` command.
It supports a small subset of the `bash` history command:
http:// my -server.com> history
http:// my -server.com> history 5
|
bin/presto
view on Meta::CPAN
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | answers typically point to some horrible GUI or (on the complete opposite
end of the spectrum) just using C<curl> directly on the command-line.
This tool attempts to find some sort of middle ground by providing a
quasi-DSL for interacting with a RESTful service in an interactive way.
|
bin/presto
view on Meta::CPAN
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | like the C<-B> file-test operator), the output is not printed to STDOUT.
Instead, you may want to use output redirection as show above and send the response body to a file.
http:// my -server.com> GET /some-image.jpg >foo.jpg
|
bin/presto
view on Meta::CPAN
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | Must be one of the supported modules (i.e. Data::Dumper or JSON).
Use tab completion to see currently supported values (defaults to "JSON" ).
|
lib/App/Presto.pm
view on Meta::CPAN
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | is => 'lazy' ,
);
sub _build_client {
my $self = shift ;
return App::Presto::Client->new( config => $self ->config);
}
has config => (
is => 'rw' ,
handles => [ 'endpoint' ],
);
has _stash => (
is => 'lazy' ,
handles => [ 'stash' ],
);
sub _build__stash {
my $self = shift ;
return App::Presto::Stash->new;
|
lib/App/Presto.pm
view on Meta::CPAN
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | },
"history" => {
exclude_from_completion => 1,
exclude_from_history => 1,
desc => "Prints the command history" ,
args => "[-c] [-d] [number]" ,
method => sub { shift ->history_call( @_ ) },
doc => "Specify a number to list the last N lines of history Pass -c to clear the command history, -d NUM to delete a single item\n" ,
},
},
prompt => sprintf ( '%s> ' , $self ->endpoint ),
history_file => $self ->config->file( 'history' ),
);
$term ->ornaments( 'md,me,,' );
return $term ;
}
has command_factory => (
is => 'lazy' ,
);
sub _build_command_factory { return App::Presto::CommandFactory->new }
|
lib/App/Presto.pm
view on Meta::CPAN
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | my $SINGLETON ;
sub instance {
my $class = shift ;
return $SINGLETON ||= $class ->new( @_ );
}
sub run {
my $class = shift ;
my $self = $class ->instance;
my @args = shift ;
my $config ;
if ( my $endpoint = shift ( @args )){
$self ->config( $config = App::Presto::Config->new( endpoint => $endpoint ) );
} else {
}
$config ->init_defaults;
$self ->command_factory->install_commands( $self );
my $binmode = $config ->get( 'binmode' );
binmode (STDOUT, ":encoding($binmode)" );
binmode (STDIN, ":encoding($binmode)" );
|
lib/App/Presto/Client.pm
view on Meta::CPAN
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | my $uri = $self ->_make_uri( shift );
$self ->_rest_client->PUT( $uri , shift );
}
sub _make_uri {
my $self = shift ;
my $local_uri = shift ;
my @args = @_ ;
my $config = $self ->config;
my $endpoint ;
$local_uri = '/' if ! defined $local_uri ;
$local_uri = URI->new( $local_uri );
if ( $local_uri ->scheme ) {
$endpoint = $local_uri ;
} else {
my $local_path = $local_uri ->path;
$endpoint = $config ->endpoint;
$endpoint .= '*' unless $endpoint =~ m/\*/;
$endpoint =~ s{\*}{ $local_path };
$endpoint .= '?' . $local_uri ->query if $local_uri ->query;
}
my $u = $self ->_append_query_params( $endpoint , @args );
return "$u" ;
}
sub _append_query_params {
my $self = shift ;
my $u = URI->new( shift );
my @args = @_ ;
foreach my $next ( @args ) {
$u ->query_param_append( split ( /=/, $next , 2 ) );
}
|
lib/App/Presto/Config.pm
view on Meta::CPAN
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | our $AUTHORITY = 'cpan:MPERRY' ;
$App::Presto::Config::VERSION = '0.010' ;
use JSON qw(decode_json encode_json) ; has endpoint => (
is => 'rw' ,
required => 1,
trigger => sub { delete shift ->{endpoint_dir} }
);
has config => (
is => 'lazy' ,
clearer => 'reload' ,
isa => sub { die "not a HashRef" if ref ( $_ [0]) ne 'HASH' ; },
);
sub _build_config {
my $self = shift ;
my $config_file = $self ->file( 'config.json' );
if (! -e $config_file ) {
|
lib/App/Presto/Config.pm
view on Meta::CPAN
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | my $json_text = < $fh >;
$config = decode_json( $json_text || '{}' );
1;
} or do {
warn "Ignoring invalid config file $config_file: $@\n" ;
$config = {};
};
return $config ;
}
has endpoint_dir => (
is => 'lazy' ,
);
sub _build_endpoint_dir {
my $self = shift ;
my $root = $ENV {APP_REST_CLI_DIR} || sprintf ( '%s/.app-presto' , File::HomeDir->my_home);
( my $endpoint_dir = lc $self ->endpoint) =~ s/\W+/-/g;
my $dir = sprintf ( '%s/%s' , $root , $endpoint_dir );
if (!-d $dir ){
warn "creating directory $dir\n" ;
make_path( $dir );
}
return $dir ;
}
sub file {
my $self = shift ;
( my $file = shift ) =~ s{^[\./]+}{}g;
return sprintf ( '%s/%s' , $self ->endpoint_dir, $file );
}
sub is_set {
my $self = shift ;
my $key = shift ;
return exists $self ->config->{ $key };
}
sub set {
my $self = shift ;
my $key = shift ;
my $value = shift ;
if ( $key eq 'endpoint' ){
return $self ->endpoint( $value );
}
if (! defined $value ){
delete $self ->config->{ $key };
} else {
$self ->config->{ $key } = $value ;
}
eval {
$self ->write_config;
1;
} or do {
|
lib/App/Presto/Config.pm
view on Meta::CPAN
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | return ;
}
sub unset {
my $self = shift ;
return $self ->set( $_ [0], undef );
}
sub get {
my $self = shift ;
my $key = shift ;
return $self ->endpoint if $key eq 'endpoint' ;
return exists $self ->config->{ $key } ? $self ->config->{ $key } : undef ;
}
sub keys {
my $self = shift ;
return keys %{ $self ->config };
}
sub write_config {
my $self = shift ;
|
lib/App/Presto/Config.pm
view on Meta::CPAN
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | |
t/02-config.t
view on Meta::CPAN
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | my $EMPTY = $d . 'empty-config' ;
my $EXISTING = $d . 'config' ;
my $FAKE_HOME = $d . 'config/fake-home' ;
subtest 'empty config' => sub {
local $ENV {APP_REST_CLI_DIR} = $EMPTY ;
remove_tree( $EMPTY , { keep_root => 1 } );
my @warnings = capture_warnings {
like $config ->endpoint_dir, qr{myserver} ,
'config dir reflects endpoint name' ;
};
like $warnings [0], qr{creating directory} ,
'warnings about creating directory' ;
@warnings = capture_warnings {
$config ->set( foo => 'bar' );
};
like $warnings [0], qr{creating new config file} , 'warns about creating new config file' ;
is $config ->get( 'foo' ), 'bar' , 'get' ;
|
t/02-config.t
view on Meta::CPAN
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | $config ->unset( 'foo' );
is_deeply [ $config -> keys ], [], 'empty keys' ;
remove_tree( $EMPTY );
};
subtest 'existing config' => sub {
local $ENV {APP_REST_CLI_DIR} = $EXISTING ;
my @warnings = capture_warnings {
like $config ->endpoint_dir, qr{myserver} ,
'config dir reflects endpoint name' ;
};
ok ! @warnings , 'no warnings' or diag explain $config , \ @warnings ;
like $config ->file( 'foo' ), qr{/foo} , 'file has correct name' ;
like $config ->endpoint_dir, qr{anotherserver} , 'new endpoint == new endpoint_dir' ;
};
subtest 'new endpoint' => sub {
local $ENV {APP_REST_CLI_DIR} = $EXISTING ;
my @warnings = capture_warnings {
like $config ->endpoint_dir, qr{myserver} ,
'config dir reflects endpoint name' ;
};
ok ! @warnings , 'no warnings' or diag explain $config , \ @warnings ;
is $config ->get( 'foo' ), 1, 'loaded correctly' ;
like $config ->file( 'foo' ), qr{/foo} , 'file has correct name' ;
like $config ->endpoint_dir, qr{anotherserver} , 'new endpoint == new endpoint_dir' ;
};
subtest 'home directory' => sub {
no warnings 'redefine' ;
*File::HomeDir::my_home = sub { $FAKE_HOME };
my @warnings = capture_warnings {
like $config ->endpoint_dir, qr{fake-home/\.app-presto/http-myserver-com} , 'created in home directory' ;
};
ok @warnings , 'warns about creating new directory' ;
remove_tree $FAKE_HOME ;
};
done_testing;
|
t/04-client.t
view on Meta::CPAN
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | my $config = Test::MockObject->new;
my $rest_client = Test::MockObject->new;
$rest_client ->set_true( 'GET' , 'DELETE' , 'PUT' , 'POST' , 'HEAD' , 'request' );
my %headers ;
$rest_client ->mock( 'addHeader' , sub { shift ; my ( $k , $v ) = @_ ; $headers { $k } = $v ; });
$rest_client ->{_headers} = \ %headers ;
my $client = App::Presto::Client->new( config => $config , _rest_client => $rest_client );
isa_ok( $client , 'App::Presto::Client' );
|
t/04-client.t
view on Meta::CPAN
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | }
$client ->PUT( '/bar' , 'foobar' );
{
my ( $m , $args ) = $rest_client ->next_call;
is $m , 'PUT' , 'rest_client PUT' ;
is $args ->[2], 'foobar' , 'PUT body' ;
}
$client ->PUT( '/bar?blah=1' , 'foobar' );
{
my ( $m , $args ) = $rest_client ->next_call;
is $m , 'PUT' , 'rest_client PUT' ;
}
$client ->HEAD;
{
my ( $m , $args ) = $rest_client ->next_call;
is $m , 'HEAD' , 'rest_client HEAD (no uri)' ;
}
$client ->POST( '/foo' , q({"a":1}) );
{
|