File Coverage

blib/lib/Swagger2.pm
Criterion Covered Total %
statement 81 81 100.0
branch 25 28 89.2
condition 25 27 92.5
subroutine 20 20 100.0
pod 11 11 100.0
total 162 167 97.0


line stmt bran cond sub pod time code
1             package Swagger2;
2 36     36   724648 use Mojo::Base -base;
  36         45  
  36         201  
3 36     36   4853 use Mojo::Asset::File;
  36         73493  
  36         295  
4 36     36   1942 use Mojo::JSON;
  36         34078  
  36         1017  
5 36     36   1414 use Mojo::JSON::Pointer;
  36         1338  
  36         245  
6 36     36   1762 use Mojo::URL;
  36         14909  
  36         186  
7 36     36   590 use File::Basename ();
  36         42  
  36         450  
8 36     36   111 use File::Spec;
  36         34  
  36         642  
9 36     36   14754 use JSON::Validator::OpenAPI;
  36         387804  
  36         35515  
10              
11             our $VERSION = '0.88';
12              
13             # Should be considered internal
14             our $JS_CLIENT
15             = File::Spec->catfile(File::Basename::dirname(__FILE__), 'Swagger2', 'swagger2-client.js');
16              
17             has api_spec => sub {
18             my $self = shift;
19             return $self->_validator->_load_schema($self->url) if '' . $self->url;
20             return Mojo::JSON::Pointer->new({});
21             };
22              
23             has base_url => sub {
24             my $self = shift;
25             my $url = Mojo::URL->new;
26             my ($schemes, $v);
27              
28             $self->load if !$self->{api_spec} and '' . $self->url;
29             $schemes = $self->api_spec->get('/schemes') || [];
30             $url->host($self->api_spec->get('/host') || 'example.com');
31             $url->path($self->api_spec->get('/basePath') || '/');
32             $url->scheme($schemes->[0] || 'http');
33              
34             return $url;
35             };
36              
37             has _specification => sub { shift->_validator->schema('http://swagger.io/v2/schema.json')->schema };
38              
39             has _validator => sub { JSON::Validator::OpenAPI->new };
40              
41 1     1 1 206 sub ua { shift->_validator->ua(@_) }
42 153     153 1 97684 sub url { shift->{url} }
43              
44             sub expand {
45 88     88 1 267 my $self = shift;
46 88         398 my $class = Scalar::Util::blessed($self);
47 88         221 my $schema = $self->_validator->schema($self->api_spec->data)->schema;
48 88         123556 $class->new(%$self)->api_spec($schema);
49             }
50              
51             sub find_operations {
52 7     7 1 2921 my ($self, $needle) = @_;
53 7         18 my $paths = $self->api_spec->get('/paths');
54 7         134 my $operations = [];
55              
56 7   100     14 $needle ||= {};
57 7 100       14 $needle = {operationId => $needle} unless ref $needle;
58              
59 7         15 for my $path (keys %$paths) {
60 21 50       33 next if $path =~ /^x-/;
61 21 100 100     42 next if $needle->{path} and $needle->{path} ne $path;
62 17         10 for my $method (keys %{$paths->{$path}}) {
  17         31  
63 31         31 my $object = $paths->{$path}{$method};
64 31 100       50 next if $method =~ /^x-/;
65 24 100 100     36 next if $needle->{tag} and !grep { $needle->{tag} eq $_ } @{$object->{tags} || []};
  6 100       18  
  8         23  
66 17 100 100     30 next if $needle->{method} and $needle->{method} ne $method;
67 16 100 100     37 next if $needle->{operationId} and $needle->{operationId} ne $object->{operationId};
68 10         12 push @$operations, $object;
69             }
70             }
71              
72 7         13 return $operations;
73             }
74              
75 1     1 1 11 sub javascript_client { Mojo::Asset::File->new(path => $JS_CLIENT) }
76              
77             sub load {
78 48     48 1 69 my $self = shift;
79 48         61 delete $self->{base_url};
80 48 100       193 $self->{url} = Mojo::URL->new(shift) if @_;
81 48         3517 $self->{api_spec} = $self->api_spec;
82 48         71405 $self;
83             }
84              
85             sub new {
86 147     147 1 490198 my $class = shift;
87 147 100       370 my $url = @_ % 2 ? shift : '';
88 147         471 my $self = $class->SUPER::new(@_);
89              
90 147         710 $url =~ s!^file://!!;
91 147   100     674 $self->{url} ||= $url;
92 147 100       890 $self->{url} = Mojo::URL->new($self->{url}) unless ref $self->{url};
93 147         15401 $self;
94             }
95              
96             sub parse {
97 4     4 1 93 my ($self, $doc, $namespace) = @_;
98 4         5 delete $self->{base_url};
99 4   100     17 $namespace ||= 'http://127.0.0.1/#';
100 4         12 $self->{url} = Mojo::URL->new($namespace);
101 4         308 $self->{api_spec} = Mojo::JSON::Pointer->new($self->_validator->_load_schema_from_text($doc));
102 4         8103 $self;
103             }
104              
105             sub pod {
106 12     12 1 7795 my $self = shift;
107 12         36 my $resolved = $self->_validator->schema($self->api_spec->data)->schema;
108 12         42414 require Swagger2::POD;
109 12         46 Swagger2::POD->new(base_url => $self->base_url, api_spec => $resolved);
110             }
111              
112             sub to_string {
113 2     2 1 1602 my $self = shift;
114 2   100     7 my $format = shift || 'json';
115              
116 2 50       5 return DumpYAML($self->api_spec->data) if $format eq 'yaml';
117 2         5 return Mojo::JSON::encode_json($self->api_spec->data);
118             }
119              
120             sub validate {
121 43     43 1 23100 my $self = shift;
122 43         120 $self->_validator->validate($self->expand->api_spec->data, $self->_specification->data);
123             }
124              
125             sub _is_true {
126 120 50 66 120   274 return $_[0] if ref $_[0] and !Scalar::Util::blessed($_[0]);
127 120 100 66     484 return 0 if !$_[0] or $_[0] =~ /^(n|false|off)/i;
128 110         570 return 1;
129             }
130              
131             1;
132              
133             =encoding utf8
134              
135             =head1 NAME
136              
137             Swagger2 - Swagger RESTful API Documentation
138              
139             =head1 VERSION
140              
141             0.88
142              
143             =head1 DEPRECATION WARNING
144              
145             The L distribution is no longer actively maintained. Only severe bug
146             fixes and pull requests will move this code forward. The reason behind this is
147             that the code is too complex and hard to maintain.
148              
149             So what should you use instead?
150              
151             =over 2
152              
153             =item * L
154              
155             L is either not very useful or replaced by L.
156              
157             =item * L
158              
159             No alternatives. The issue with this module is that it does not understand if
160             you have parameters with the same name. There might be a L at
161             some point, but it is currently no plans to write it.
162              
163             =item * L
164              
165             No alternatives.
166              
167             =item * L
168              
169             L is not very good and also very hard to maintain.
170             L has a HTML renderer which makes documentation
171             that is much easier to read and always in sync with the application.
172              
173             When that is said: The renderer in L need
174             refinement.
175              
176             =item * L
177              
178             L has the validator built in. For other purposes,
179             use L or L instead.
180              
181             =item * L
182              
183             No alternatives.
184              
185             =item * L
186              
187             Use L instead. L
188             plays much nicer together with the L framework.
189              
190             =back
191              
192             =head1 DESCRIPTION
193              
194             L is a module for generating, parsing and transforming
195             L API specification. It has support for reading
196             swagger specification in JSON notation and as well YAML format.
197              
198             Please read L
199             for an introduction to Swagger and reasons for why you would to use it.
200              
201             =head2 Mojolicious server side code generator
202              
203             This distribution comes with a L plugin,
204             L, which can set up routes and perform input
205             and output validation.
206              
207             =head2 Mojolicious client side code generator
208              
209             Swagger2 also comes with a L generator, which converts the client
210             spec to perl code in memory.
211              
212             =head1 RECOMMENDED MODULES
213              
214             =over 4
215              
216             =item * YAML parser
217              
218             A L parser is required if you want to read/write spec written in
219             the YAML format. Supported modules are L, L, L
220             and L.
221              
222             =back
223              
224             =head1 SYNOPSIS
225              
226             use Swagger2;
227             my $swagger = Swagger2->new("/path/to/api-spec.yaml");
228              
229             # Access the raw specification values
230             print $swagger->api_spec->get("/swagger");
231              
232             # Returns the specification as a POD document
233             print $swagger->pod->to_string;
234              
235             =head1 ATTRIBUTES
236              
237             =head2 api_spec
238              
239             $pointer = $self->api_spec;
240             $self = $self->api_spec(Mojo::JSON::Pointer->new({}));
241              
242             Holds a L object containing your API specification.
243              
244             =head2 base_url
245              
246             $mojo_url = $self->base_url;
247              
248             L object that holds the location to the API endpoint.
249             Note: This might also just be a dummy URL to L.
250              
251             =head2 ua
252              
253             $ua = $self->ua;
254             $self = $self->ua(Mojo::UserAgent->new);
255              
256             A L used to fetch remote documentation.
257              
258             =head2 url
259              
260             $mojo_url = $self->url;
261              
262             L object that holds the location to the documentation file.
263             This can be both a location on disk or an URL to a server. A remote
264             resource will be fetched using L.
265              
266             =head1 METHODS
267              
268             =head2 expand
269              
270             $swagger = $self->expand;
271              
272             This method returns a new C object, where all the
273             L
274             are resolved.
275              
276             =head2 find_operations
277              
278             $operations = $self->find_operations(\%q);
279              
280             Used to find a list of L
281             from the specification. C<%q> can be:
282              
283             $all = $self->find_operations;
284             $operations = $self->find_operations($operationId);
285             $operations = $self->find_operations({operationId => "listPets"});
286             $operations = $self->find_operations({method => "post", path => "/pets"});
287             $operations = $self->find_operations({tag => "pets"});
288              
289             =head2 javascript_client
290              
291             $file = $self->javascript_client;
292              
293             Returns a L object which points to a file containing a
294             custom JavaScript file which can communicate with
295             L.
296              
297             See L
298             for source code.
299              
300             C is currently EXPERIMENTAL!
301              
302             =head2 load
303              
304             $self = $self->load;
305             $self = $self->load($url);
306              
307             Used to load the content from C<$url> or L. This method will try to
308             guess the content type (JSON or YAML) by looking at the content of the C<$url>.
309              
310             =head2 new
311              
312             $self = Swagger2->new($url);
313             $self = Swagger2->new(%attributes);
314             $self = Swagger2->new(\%attributes);
315              
316             Object constructor.
317              
318             =head2 parse
319              
320             $self = $self->parse($text);
321              
322             Used to parse C<$text> instead of L data from L.
323              
324             The type of input text can be either JSON or YAML. It will default to YAML,
325             but parse the text as JSON if it starts with "{".
326              
327             =head2 pod
328              
329             $pod_object = $self->pod;
330              
331             Returns a L object.
332              
333             =head2 to_string
334              
335             $json = $self->to_string;
336             $json = $self->to_string("json");
337             $yaml = $self->to_string("yaml");
338              
339             This method can transform this object into Swagger spec.
340              
341             =head2 validate
342              
343             @errors = $self->validate;
344              
345             Will validate L against
346             L,
347             and return a list with all the errors found. See also L.
348              
349             =head1 COPYRIGHT AND LICENSE
350              
351             Copyright (C) 2014-2015, Jan Henning Thorsen
352              
353             This program is free software, you can redistribute it and/or modify it under
354             the terms of the Artistic License version 2.0.
355              
356             =head1 AUTHOR
357              
358             Jan Henning Thorsen - C
359              
360             =cut