APISchema

 view release on metacpan or  search on metacpan

README.md  view on Meta::CPAN

            controller  => 'BMI',
            action      => 'calculate',
        },
        request         => 'figure',
        response        => 'bmi',
    };

    # main.pl

    use APISchema::DSL;
    my $schema = APISchema::DSL::process {
        include 'bmi.def';
    };

    # Routing
    use APISchema::Generator::Router::Simple;
    my $router = do {
        my $generator = APISchema::Generator::Router::Simple->new;
        $generator->generate_router($schema);
    };

eg/bmi.psgi  view on Meta::CPAN

use Plack::Builder;
use Plack::Request;
use APISchema::DSL;
use APISchema::Generator::Router::Simple;
use Plack::App::APISchema::Document;
use Plack::App::APISchema::MockServer;
use APISchema::Generator::Markdown;

use JSON qw(decode_json encode_json);

my $schema = APISchema::DSL::process {
    include '../t/fixtures/bmi.def';
};

my $router = do {
    my $generator = APISchema::Generator::Router::Simple->new;
    $generator->generate_router($schema);
};

my $app = sub {
    my $env = shift;

lib/APISchema.pm  view on Meta::CPAN

            controller  => 'BMI',
            action      => 'calculate',
        },
        request         => 'figure',
        response        => 'bmi',
    };

    # main.pl

    use APISchema::DSL;
    my $schema = APISchema::DSL::process {
        include 'bmi.def';
    };

    # Routing
    use APISchema::Generator::Router::Simple;
    my $router = do {
        my $generator = APISchema::Generator::Router::Simple->new;
        $generator->generate_router($schema);
    };

lib/APISchema/DSL.pm  view on Meta::CPAN


our %METHODS = (
    ( map { $_ => $_ } qw(HEAD GET POST PUT DELETE PATCH) ),
    FETCH => [qw(GET HEAD)],
);
our @DIRECTIVES = (qw(include filter resource title description), keys %METHODS);
our @EXPORT = @DIRECTIVES;

my $_directive = {};

sub process (&) {
    my $dsl = shift;

    my $schema = APISchema::Schema->new;

    local $_directive->{include} = sub {
        my ($file) = @_;
        -r $_[0] or Carp::croak(sprintf 'No such file: %s', $file);
        my $content = file($file)->slurp;
        my $with_utf8 = "use utf8;\n" . $content;
        eval $with_utf8;

lib/APISchema/DSL.pm  view on Meta::CPAN

sub filter (&) { $_directive->{filter}->(@_) }
sub resource ($@) { $_directive->{resource}->(@_) }
for my $method (keys %METHODS) {
    no strict 'refs';
    *$method = sub ($@) { goto \&{ $_directive->{$method} } };
}

# disable the global definitions
@$_directive{@DIRECTIVES} = (sub {
    Carp::croak(sprintf(
        q(%s should be called inside 'process {}' block),
        join '/', @DIRECTIVES
    ));
}) x scalar @DIRECTIVES;

1;
__END__

script/generate_markdown_document.pl  view on Meta::CPAN


unless ($ARGV[0]) {
    print <<EOM;
Usage: $0 <file>
Options:
  <file>    API definition file.
EOM
    exit;
}

my $schema = APISchema::DSL::process {
    include $ARGV[0];
};

my $generator = APISchema::Generator::Markdown->new;
print encode_utf8 $generator->format_schema($schema);

t/APISchema-DSL.t  view on Meta::CPAN

    dies_ok {
        GET '/' => ();
    };

    dies_ok {
        POST '/' => ();
    };

}

sub process : Tests {
    lives_ok {
        my $schema = APISchema::DSL::process {};
        isa_ok $schema, 'APISchema::Schema';
    };

    dies_ok {
        GET '/' => ();
    };

    subtest 'title, description' => sub {
        lives_ok {
            my $schema = APISchema::DSL::process {
                title 'BMI API';
                description 'The API to calculate BMI';
            };
            isa_ok $schema, 'APISchema::Schema';
            is $schema->title, 'BMI API';
            is $schema->description, 'The API to calculate BMI';
        };
    };

    subtest 'Simple GET' => sub {
        lives_ok {
            my $schema = APISchema::DSL::process {
                GET '/' => {
                    title       => 'Simple GET',
                    destination => { some => 'property' },
                };
            };
            isa_ok $schema, 'APISchema::Schema';

            my $routes = $schema->get_routes;
            is scalar @$routes, 1;

            is $routes->[0]->route, '/';
            is $routes->[0]->title, 'Simple GET';
            is_deeply $routes->[0]->destination, { some => 'property' };
        };
    };

    subtest 'Support PATCH' => sub {
        lives_ok {
            my $schema = APISchema::DSL::process {
                PATCH '/my' => {
                    title       => 'Update My BMI',
                    destination => {
                        controller => 'BMI',
                        action     => 'update',
                    },
                };
            };
            isa_ok $schema, 'APISchema::Schema';

t/APISchema-DSL.t  view on Meta::CPAN

            is $routes->[0]->method, 'PATCH';
            is_deeply $routes->[0]->destination, {
                controller => 'BMI',
                action     => 'update',
            };
        };
    };

    subtest 'Validation should be returned' => sub {
        lives_ok {
            my $schema = APISchema::DSL::process {
                title 'BMI API';
                description 'The API to calculate BMI';

                resource figure => {
                    type => 'object',
                    description => 'Figure, which includes weight and height',
                    properties => {
                        weight  => {
                            type => 'number',
                            description => 'Weight(kg)',

t/APISchema-DSL.t  view on Meta::CPAN

            };
            cmp_deeply $routes->[0]->option, { on_match => code(sub { 1 }) };
            is $routes->[0]->request_resource, 'figure';
            is $routes->[0]->response_resource, 'bmi';
        };
    };
}

sub from_file : Tests {
    lives_ok {
        my $schema = APISchema::DSL::process {
            include 't/fixtures/bmi.def';
        };

        isa_ok $schema, 'APISchema::Schema';

        is $schema->title, 'BMI API';
        is $schema->description, 'The API to calculate BMI';

        is_deeply [ sort {
            $a->title cmp $b->title;

t/APISchema-DSL.t  view on Meta::CPAN

        is_deeply $routes->[0]->destination, {
            controller => 'BMI',
            action     => 'calculate',
        };
        cmp_deeply $routes->[0]->option, { on_match => code(sub { 1 }) };
        is $routes->[0]->request_resource, 'figure';
        is $routes->[0]->response_resource, 'bmi';
    };

    dies_ok {
        my $schema = APISchema::DSL::process {
            include 'not-such-file';
        };
    };

    dies_ok {
        my $schema = APISchema::DSL::process {
            include 't/fixtures/syntax-error.def';
        };
    };

    dies_ok {
        my $schema = APISchema::DSL::process {
            include 't/fixtures/runtime-error.def';
        };
    };
}

sub with_unicode : Tests {
    my $schema = APISchema::DSL::process {
        include 't/fixtures/user.def';
    };

    isa_ok $schema, 'APISchema::Schema';

    is $schema->title, decode_utf8('ユーザー');
    is $schema->description, decode_utf8('ユーザーの定義');

    cmp_deeply $schema->get_resource_by_name('user')->{definition}, {
        type => 'object',

t/APISchema-Generator-Markdown.t  view on Meta::CPAN

        my $schema = t::test::fixtures::prepare_status;

        my $generator = APISchema::Generator::Markdown->new;
        my $markdown = $generator->format_schema($schema);
        like $markdown, qr{#### Response `200 OK`};
        like $markdown, qr{\nHTTP/1.1 200 OK\nSucceeded!\n};
        like $markdown, qr{#### Response `400 Bad Request`};
    };

    subtest 'example with no containers' => sub {
        my $schema = APISchema::DSL::process {
          resource gender => {
            enum => ['male', 'female', 'other'],
            example => 'other',
          };
        };

        my $generator = APISchema::Generator::Markdown->new;
        my $markdown = $generator->format_schema($schema);

        like $markdown, qr/^"other"$/m;
    };

    subtest 'FETCH endpoint' => sub {
        my $schema = APISchema::DSL::process {
            FETCH '/' => {
                title => 'Fetch',
                destination => {},
            };
        };

        my $generator = APISchema::Generator::Markdown->new;
        my $markdown = $generator->format_schema($schema);

        like $markdown, qr{\Q- [Fetch](#route-Fetch) - `GET`, `HEAD` /\E}, 'FETCH expanded to GET and HEAD';

t/test/fixtures.pm  view on Meta::CPAN

package t::test::fixtures;
use strict;
use warnings;
use APISchema::DSL;

sub prepare_bmi {
    APISchema::DSL::process {
        include 't/fixtures/bmi.def';
    };
}

sub prepare_family {
    APISchema::DSL::process {
        include 't/fixtures/family.def';
    };
}

sub prepare_user {
    APISchema::DSL::process {
        include 't/fixtures/user.def';
    };
}

sub prepare_author {
    APISchema::DSL::process {
        include 't/fixtures/author.def';
    };
}

sub prepare_status {
    APISchema::DSL::process {
        include 't/fixtures/status.def';
    };
}

sub prepare_boolean {
    APISchema::DSL::process {
        include 't/fixtures/boolean.def';
    };
}

sub prepare_example_null {
    APISchema::DSL::process {
        include 't/fixtures/example-null.def';
    };
}

1;



( run in 0.292 second using v1.01-cache-2.11-cpan-8d75d55dd25 )