File Coverage

blib/lib/CPAN/Testers/API.pm
Criterion Covered Total %
statement 56 60 93.3
branch 1 2 50.0
condition n/a
subroutine 10 11 90.9
pod 2 2 100.0
total 69 75 92.0


line stmt bran cond sub pod time code
1             package CPAN::Testers::API;
2             our $VERSION = '0.018';
3             # ABSTRACT: REST API for CPAN Testers data
4              
5             #pod =head1 SYNOPSIS
6             #pod
7             #pod $ cpantesters-api daemon
8             #pod Listening on http://*:5000
9             #pod
10             #pod =head1 DESCRIPTION
11             #pod
12             #pod This is a REST API on to the data contained in the CPAN Testers
13             #pod database. This data includes test reports, CPAN distributions, and
14             #pod various aggregate test reporting.
15             #pod
16             #pod =head1 CONFIG
17             #pod
18             #pod This application can be configured by setting the C<MOJO_CONFIG>
19             #pod environment variable to the path to a configuration file. The
20             #pod configuration file is a Perl script containing a single hash reference,
21             #pod like:
22             #pod
23             #pod # api.conf
24             #pod {
25             #pod broker => 'ws://127.0.0.1:5000',
26             #pod }
27             #pod
28             #pod The possible configuration keys are below:
29             #pod
30             #pod =head2 broker
31             #pod
32             #pod The URL to a L<Mercury> message broker, starting with C<ws://>. This
33             #pod broker is used to forward messages to every connected user.
34             #pod
35             #pod =head1 SEE ALSO
36             #pod
37             #pod L<Mojolicious>, L<Mojolicious::Plugin::OpenAPI>,
38             #pod L<CPAN::Testers::Schema>,
39             #pod L<http://github.com/cpan-testers/cpantesters-project>,
40             #pod L<http://www.cpantesters.org>
41             #pod
42             #pod =cut
43              
44 5     5   5029808 use Mojo::Base 'Mojolicious';
  5         13  
  5         53  
45 5     5   184118 use CPAN::Testers::API::Base;
  5         19  
  5         50  
46 5     5   169 use File::Share qw( dist_dir dist_file );
  5         66  
  5         285  
47 5     5   1535 use Log::Any::Adapter;
  5         1323  
  5         18  
48 5     5   1395 use Alien::SwaggerUI;
  5         611  
  5         135  
49 5     5   27 use File::Spec::Functions qw( catdir catfile );
  5         10  
  5         2807  
50              
51             #pod =method schema
52             #pod
53             #pod my $schema = $c->schema;
54             #pod
55             #pod Get the schema, a L<CPAN::Testers::Schema> object. By default, the
56             #pod schema is connected from the local user's config. See
57             #pod L<CPAN::Testers::Schema/connect_from_config> for details.
58             #pod
59             #pod =cut
60              
61             has schema => sub {
62             require CPAN::Testers::Schema;
63             return CPAN::Testers::Schema->connect_from_config;
64             };
65              
66             #pod =method startup
67             #pod
68             #pod # Called automatically by Mojolicious
69             #pod
70             #pod This method starts up the application, loads any plugins, sets up routes,
71             #pod and registers helpers.
72             #pod
73             #pod =cut
74              
75 5     5 1 3133318 sub startup ( $app ) {
  5         13  
  5         11  
76 5         44 $app->log( Mojo::Log->new ); # Log only to STDERR
77 5         148 unshift @{ $app->renderer->paths },
  5         16  
78             catdir( dist_dir( 'CPAN-Testers-API' ), 'templates' );
79 5         953 unshift @{ $app->static->paths },
  5         25  
80             catdir( dist_dir( 'CPAN-Testers-API' ), 'public' );
81              
82 5         577 $app->moniker( 'api' );
83 5         128 $app->plugin( Config => {
84             default => { }, # Allow living without config file
85             } );
86              
87             # Allow CORS for everyone
88             $app->hook( after_build_tx => sub {
89 50     50   678503 my ( $tx, $app ) = @_;
90 50         223 $tx->res->headers->header( 'Access-Control-Allow-Origin' => '*' );
91 50         3670 $tx->res->headers->header( 'Access-Control-Allow-Methods' => 'GET, POST, PUT, PATCH, DELETE, OPTIONS' );
92 50         1305 $tx->res->headers->header( 'Access-Control-Max-Age' => 3600 );
93 50         1159 $tx->res->headers->header( 'Access-Control-Allow-Headers' => 'Content-Type, X-Requested-With' );
94 5         6055 } );
95              
96 5         64 my $r = $app->routes;
97 5         62 $r->get( '/' => 'index' );
98             $r->get( '/docs/*path' => { path => 'index.html' } )->to(
99             cb => sub {
100 0     0   0 my ( $c ) = @_;
101 0         0 my $path = catfile( Alien::SwaggerUI->root_dir, $c->stash( 'path' ) );
102 0         0 my $file = Mojo::Asset::File->new( path => $path );
103 0         0 $c->reply->asset( $file );
104             },
105 5         1138 );
106              
107 5         1301 $r->websocket( '/v1/upload' )->to( 'Upload#feed' );
108 5         1149 $r->websocket( '/v1/upload/dist/:dist' )->to( 'Upload#feed' );
109 5         1256 $r->websocket( '/v1/upload/author/:author' )->to( 'Upload#feed' );
110              
111 5         1331 $r->websocket( '/v3/upload' )->to( 'Upload#feed' );
112 5         1026 $r->websocket( '/v3/upload/dist/:dist' )->to( 'Upload#feed' );
113 5         1315 $r->websocket( '/v3/upload/author/:author' )->to( 'Upload#feed' );
114              
115 5         1395 $app->plugin( OpenAPI => {
116             url => dist_file( 'CPAN-Testers-API' => 'v1.json' ),
117             allow_invalid_ref => 1,
118             } );
119 5         1709343 $app->plugin( OpenAPI => {
120             url => dist_file( 'CPAN-Testers-API' => 'v3.json' ),
121             allow_invalid_ref => 1,
122             } );
123 5     37   2424491 $app->helper( schema => sub { shift->app->schema } );
  37         1381  
124 5         149 $app->helper( render_error => \&render_error );
125              
126 5         76 Log::Any::Adapter->set( 'MojoLog', logger => $app->log );
127             }
128              
129             #pod =method render_error
130             #pod
131             #pod return $c->render_error( 400 => 'Bad Request' );
132             #pod return $c->render_error( 400, {
133             #pod path => '/since',
134             #pod message => 'Invalid date/time',
135             #pod } );
136             #pod
137             #pod Render an error in JSON like other OpenAPI errors. The first argument
138             #pod is the HTTP status code. The remaining arguments are a list of errors
139             #pod to report. Plain strings are turned into one-element hashrefs with a
140             #pod C<message> key. Hashrefs are used as-is.
141             #pod
142             #pod The resulting JSON looks like so:
143             #pod
144             #pod {
145             #pod "errors": [
146             #pod {
147             #pod "path": "/",
148             #pod "message": "Bad Request"
149             #pod }
150             #pod ]
151             #pod }
152             #pod
153             #pod {
154             #pod "errors": [
155             #pod {
156             #pod "path": "/since",
157             #pod "message": "Invalid date/time"
158             #pod }
159             #pod ]
160             #pod }
161             #pod
162             #pod =cut
163              
164 11     11 1 444 sub render_error( $c, $status, @errors ) {
  11         24  
  11         21  
  11         25  
  11         18  
165             return $c->render(
166             status => $status,
167             openapi => {
168             errors => [
169 11 50       32 map { !ref $_ ? { message => $_, path => '/' } : $_ } @errors,
  11         151  
170             ],
171             },
172             );
173             }
174              
175             1;
176              
177             __END__
178              
179             =pod
180              
181             =head1 NAME
182              
183             CPAN::Testers::API - REST API for CPAN Testers data
184              
185             =head1 VERSION
186              
187             version 0.018
188              
189             =head1 SYNOPSIS
190              
191             $ cpantesters-api daemon
192             Listening on http://*:5000
193              
194             =head1 DESCRIPTION
195              
196             This is a REST API on to the data contained in the CPAN Testers
197             database. This data includes test reports, CPAN distributions, and
198             various aggregate test reporting.
199              
200             =head1 METHODS
201              
202             =head2 schema
203              
204             my $schema = $c->schema;
205              
206             Get the schema, a L<CPAN::Testers::Schema> object. By default, the
207             schema is connected from the local user's config. See
208             L<CPAN::Testers::Schema/connect_from_config> for details.
209              
210             =head2 startup
211              
212             # Called automatically by Mojolicious
213              
214             This method starts up the application, loads any plugins, sets up routes,
215             and registers helpers.
216              
217             =head2 render_error
218              
219             return $c->render_error( 400 => 'Bad Request' );
220             return $c->render_error( 400, {
221             path => '/since',
222             message => 'Invalid date/time',
223             } );
224              
225             Render an error in JSON like other OpenAPI errors. The first argument
226             is the HTTP status code. The remaining arguments are a list of errors
227             to report. Plain strings are turned into one-element hashrefs with a
228             C<message> key. Hashrefs are used as-is.
229              
230             The resulting JSON looks like so:
231              
232             {
233             "errors": [
234             {
235             "path": "/",
236             "message": "Bad Request"
237             }
238             ]
239             }
240              
241             {
242             "errors": [
243             {
244             "path": "/since",
245             "message": "Invalid date/time"
246             }
247             ]
248             }
249              
250             =head1 CONFIG
251              
252             This application can be configured by setting the C<MOJO_CONFIG>
253             environment variable to the path to a configuration file. The
254             configuration file is a Perl script containing a single hash reference,
255             like:
256              
257             # api.conf
258             {
259             broker => 'ws://127.0.0.1:5000',
260             }
261              
262             The possible configuration keys are below:
263              
264             =head2 broker
265              
266             The URL to a L<Mercury> message broker, starting with C<ws://>. This
267             broker is used to forward messages to every connected user.
268              
269             =head1 SEE ALSO
270              
271             L<Mojolicious>, L<Mojolicious::Plugin::OpenAPI>,
272             L<CPAN::Testers::Schema>,
273             L<http://github.com/cpan-testers/cpantesters-project>,
274             L<http://www.cpantesters.org>
275              
276             =head1 AUTHOR
277              
278             Doug Bell <preaction@cpan.org>
279              
280             =head1 CONTRIBUTOR
281              
282             =for stopwords Breno G. de Oliveira
283              
284             Breno G. de Oliveira <garu@cpan.org>
285              
286             =head1 COPYRIGHT AND LICENSE
287              
288             This software is copyright (c) 2016 by Doug Bell.
289              
290             This is free software; you can redistribute it and/or modify it under
291             the same terms as the Perl 5 programming language system itself.
292              
293             =cut