package Swagger2; use Mojo::Base -base; use Mojo::Asset::File; use Mojo::JSON; use Mojo::JSON::Pointer; use Mojo::URL; use Mojo::Util 'deprecated'; use File::Basename (); use File::Spec; use Swagger2::SchemaValidator; our $VERSION = '0.72'; # Should be considered internal our $SPEC_FILE = File::Spec->catfile(File::Basename::dirname(__FILE__), 'Swagger2', 'schema.json'); our $JS_CLIENT = File::Spec->catfile(File::Basename::dirname(__FILE__), 'Swagger2', 'swagger2-client.js'); has api_spec => sub { my $self = shift; return $self->_validator->_load_schema($self->url) if '' . $self->url; return Mojo::JSON::Pointer->new({}); }; has base_url => sub { my $self = shift; my $url = Mojo::URL->new; my ($schemes, $v); $self->load if !$self->{api_spec} and '' . $self->url; $schemes = $self->api_spec->get('/schemes') || []; $url->host($self->api_spec->get('/host') || 'example.com'); $url->path($self->api_spec->get('/basePath') || '/'); $url->scheme($schemes->[0] || 'http'); return $url; }; sub specification { deprecated 'specification() will be removed.'; shift->_specification; } sub tree { deprecated 'tree() is replaced by api_spec().'; shift->api_spec(@_); } has _specification => sub { shift->_validator->schema($SPEC_FILE)->schema }; has _validator => sub { Swagger2::SchemaValidator->new->cache_dir($ENV{SWAGGER2_CACHE_DIR} || File::Spec->catdir(File::Basename::dirname(__FILE__), qw( Swagger2 public cache ))); }; sub ua { shift->_validator->ua(@_) } sub url { shift->{url} } sub expand { my $self = shift; my $class = Scalar::Util::blessed($self); $class->new(%$self)->api_spec($self->_validator->schema($self->api_spec->data)->schema); } sub javascript_client { Mojo::Asset::File->new(path => $JS_CLIENT) } sub load { my $self = shift; delete $self->{base_url}; $self->{url} = Mojo::URL->new(shift) if @_; $self->{api_spec} = $self->_validator->_load_schema($self->{url}); $self; } sub new { my $class = shift; my $url = @_ % 2 ? shift : ''; my $self = $class->SUPER::new(@_); $url =~ s!^file://!!; $self->{url} ||= $url; $self->{url} = Mojo::URL->new($self->{url}) unless ref $self->{url}; $self; } sub parse { my ($self, $doc, $namespace) = @_; delete $self->{base_url}; $namespace ||= 'http://127.0.0.1/#'; $self->{url} = Mojo::URL->new($namespace); $self->{api_spec} = Mojo::JSON::Pointer->new($self->_validator->_load_schema_from_text($doc)); $self; } sub pod { my $self = shift; my $resolved = $self->_validator->schema($self->api_spec->data)->schema; require Swagger2::POD; Swagger2::POD->new(base_url => $self->base_url, api_spec => $resolved); } sub to_string { my $self = shift; my $format = shift || 'json'; if ($format eq 'yaml') { return DumpYAML($self->api_spec->data); } else { return Mojo::JSON::encode_json($self->api_spec->data); } } sub validate { my $self = shift; $self->_validator->validate($self->expand->api_spec->data, $self->_specification->data); } sub _is_true { return $_[0] if ref $_[0] and !Scalar::Util::blessed($_[0]); return 0 if !$_[0] or $_[0] =~ /^(n|false|off)/i; return 1; } 1; =encoding utf8 =head1 NAME Swagger2 - Swagger RESTful API Documentation =head1 VERSION 0.72 =head1 DESCRIPTION L<Swagger2> is a module for generating, parsing and transforming L<swagger|http://swagger.io/> API specification. It has support for reading swagger specification in JSON notation and as well YAML format. Please read L<http://thorsen.pm/perl/programming/2015/07/05/mojolicious-swagger2.html> for an introduction to Swagger and reasons for why you would to use it. =head2 Mojolicious server side code generator This distribution comes with a L<Mojolicious> plugin, L<Mojolicious::Plugin::Swagger2>, which can set up routes and perform input and output validation. =head2 Mojolicious client side code generator Swagger2 also comes with a L<Swagger2::Client> generator, which converts the client spec to perl code in memory. =head1 RECOMMENDED MODULES =over 4 =item * YAML parser A L<YAML> parser is required if you want to read/write spec written in the YAML format. Supported modules are L<YAML::XS>, L<YAML::Syck>, L<YAML> and L<YAML::Tiny>. =back =head1 SYNOPSIS use Swagger2; my $swagger = Swagger2->new("/path/to/api-spec.yaml"); # Access the raw specification values print $swagger->api_spec->get("/swagger"); # Returns the specification as a POD document print $swagger->pod->to_string; =head1 ATTRIBUTES =head2 api_spec $pointer = $self->api_spec; $self = $self->api_spec(Mojo::JSON::Pointer->new({})); Holds a L<Mojo::JSON::Pointer> object containing your API specification. =head2 base_url $mojo_url = $self->base_url; L<Mojo::URL> object that holds the location to the API endpoint. Note: This might also just be a dummy URL to L<http://example.com/>. =head2 specification DEPRECATED. If you need to change this, then you probably want L<JSON::Validator> instead. =head2 tree DEPRECATED. Use L</api_spec> instead. =head2 ua $ua = $self->ua; $self = $self->ua(Mojo::UserAgent->new); A L<Mojo::UserAgent> used to fetch remote documentation. =head2 url $mojo_url = $self->url; L<Mojo::URL> object that holds the location to the documentation file. This can be both a location on disk or an URL to a server. A remote resource will be fetched using L<Mojo::UserAgent>. =head1 METHODS =head2 expand $swagger = $self->expand; This method returns a new C<Swagger2> object, where all the L<references|https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.28> are resolved. =head2 javascript_client $file = $self->javascript_client; Returns a L<Mojo::Asset::File> object which points to a file containing a custom JavaScript file which can communicate with L<Mojolicious::Plugin::Swagger2>. See L<https://github.com/jhthorsen/swagger2/blob/master/lib/Swagger2/swagger2-client.js> for source code. C<swagger2-client.js> is currently EXPERIMENTAL! =head2 load $self = $self->load; $self = $self->load($url); Used to load the content from C<$url> or L</url>. This method will try to guess the content type (JSON or YAML) by looking at the content of the C<$url>. =head2 new $self = Swagger2->new($url); $self = Swagger2->new(%attributes); $self = Swagger2->new(\%attributes); Object constructor. =head2 parse $self = $self->parse($text); Used to parse C<$text> instead of L<loading|/load> data from L</url>. The type of input text can be either JSON or YAML. It will default to YAML, but parse the text as JSON if it starts with "{". =head2 pod $pod_object = $self->pod; Returns a L<Swagger2::POD> object. =head2 to_string $json = $self->to_string; $json = $self->to_string("json"); $yaml = $self->to_string("yaml"); This method can transform this object into Swagger spec. =head2 validate @errors = $self->validate; Will validate L</api_spec> against L<Swagger RESTful API Documentation Specification|https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md>, and return a list with all the errors found. See also L<JSON::Validator/validate>. =head1 COPYRIGHT AND LICENSE Copyright (C) 2014-2015, Jan Henning Thorsen This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0. =head1 AUTHOR Jan Henning Thorsen - C<jhthorsen@cpan.org> =cut