AtteanX-Endpoint
view release on metacpan or search on metacpan
lib/AtteanX/Endpoint.pm view on Meta::CPAN
# TODO: If the model supports caching roles, add headers and check for http 304
# TODO: Implement and support Accept-Language models (port from RDF::Trine::Store::LanguagePreference)
# TODO: Add next/prev link headers if query is paged
# TODO: Add configuration and link headers to indicate LDF/SPARQL mirrors
use v5.14;
use warnings;
package AtteanX::Endpoint {
our $VERSION = "0.003";
}
package AtteanX::Error {
use Moo;
use Types::Standard qw(Str HashRef);
use namespace::clean;
has 'message' => (is => 'ro', isa => Str, required => 1);
has 'details' => (is => 'ro', isa => HashRef, default => sub { +{} });
has 'uri' => (is => 'ro', isa => Str);
}
package AtteanX::Endpoint::Error {
use Moo;
extends 'AtteanX::Error';
use Types::Standard qw(Int);
use namespace::clean;
has 'code' => (is => 'ro', isa => Int, required => 1);
}
package AtteanX::Endpoint::ClientError {
use Moo;
extends 'AtteanX::Endpoint::Error';
use Types::Standard qw(Int);
use namespace::clean;
has 'code' => (is => 'ro', isa => Int, default => 400);
}
package AtteanX::Endpoint::ServerError {
use Moo;
extends 'AtteanX::Endpoint::Error';
use Types::Standard qw(Int);
use namespace::clean;
has 'code' => (is => 'ro', isa => Int, default => 500);
}
package Plack::App::AtteanX::Endpoint 0.003 {
use parent qw(Plack::Component);
use Plack::Request;
sub configure {
my $self = shift;
$self->{config} = shift;
return $self;
}
sub prepare_app {
my $self = shift;
my $config = $self->{config};
$self->{endpoint} = eval { AtteanX::Endpoint->new( $config ) };
if ($@) {
warn $@;
}
}
sub call {
my($self, $env) = @_;
my $req = Plack::Request->new($env);
unless ($req->method =~ /^(GET|HEAD|POST)$/) {
return [ 405, [ 'Content-type', 'text/plain' ], [ 'Method not allowed' ] ];
}
my $ep = $self->{endpoint};
my $resp = $ep->run( $req );
return $resp->finalize;
}
}
lib/AtteanX/Endpoint.pm view on Meta::CPAN
{
endpoint => {
service_description => {
named_graphs => 1,
default => 1,
},
load_data => 0,
update => 0,
}
}
=item C<< graph >>
The L<Attean::API::IRI> of the graph in the model that represents the default graph.
=back
=head1 METHODS
=over 4
=cut
package AtteanX::Endpoint {
use Moo;
use Attean;
use Attean::RDF qw(iri);
use TryCatch;
use JSON;
use Encode;
use Plack::Request;
use Plack::Response;
use Scalar::Util qw(blessed refaddr);
use List::MoreUtils qw(any);
use File::ShareDir qw(dist_dir);
use HTTP::Negotiate qw(choose);
use IO::Compress::Gzip qw(gzip);
use HTML::HTML5::Writer qw(DOCTYPE_XHTML_RDFA);
use Carp qw(croak);
use Types::Standard qw(ConsumerOf CodeRef HashRef ArrayRef Str Int);
# use IO::Handle;
# use Digest::MD5 qw(md5_base64);
use XML::LibXML 1.70;
# use RDF::RDFa::Generator 0.102;
# use Hash::Merge::Simple qw/ merge /;
# use Fcntl qw(:flock SEEK_END);
use namespace::clean;
with 'MooX::Log::Any';
has 'planner' => (
is => 'ro',
isa => ConsumerOf['Attean::API::QueryPlanner'],
required => 1,
default => sub {
Attean::IDPQueryPlanner->new();
}
);
has 'model' => (is => 'ro', isa => ConsumerOf['Attean::API::Model'], required => 1);
has 'conf' => (is => 'ro', isa => HashRef, required => 1);
has 'graph' => (is => 'ro', isa => ConsumerOf['Attean::API::IRI'], required => 1);
sub BUILDARGS {
my $class = shift;
my @params = @_;
my %args;
if (blessed($params[0]) and $params[0]->does('Attean::API::Model')) {
# ->new( $model, \%conf )
$args{ model } = shift @params;
$args{ conf } = shift @params;
$args{ graph } = Attean::IRI->new('http://example.org/graph');
} elsif (any { blessed($_) && $_->does('Attean::API::Model') } @params) {
# Assume the buildargs can be taken directly
return $class->SUPER::BUILDARGS(@params);
} else {
# ->new( \%conf )
my $conf = shift @params;
my $store_conf = $conf->{store};
my ($name_, $file) = split(';', $store_conf, 2);
my ($name, @args) = split('=', $name_);
my $sclass = Attean->get_store($name);
my $store = $sclass->new(@args);
my $model = Attean::MutableQuadModel->new( store => $store );
my $graph = Attean::IRI->new('http://example.org/graph');
if (defined($file) and length($file)) {
$graph = Attean::IRI->new('file://' . File::Spec->rel2abs($file));
open(my $fh, '<:encoding(UTF-8)', $file) or die $!;
#$self->log->debug("Parsing data from $file...");
my $pclass = Attean->get_parser( filename => $file ) // 'AtteanX::Parser::Turtle';
my $parser = $pclass->new(base => $graph);
my $iter = $parser->parse_iter_from_io($fh);
my $quads = $iter->as_quads($graph);
$model->add_iter($quads);
}
$args{ model } = $model;
$args{ conf } = $conf;
$args{ graph } = $graph;
}
return $class->SUPER::BUILDARGS(%args);
}
=item C<< run ( $request ) >>
Run the SPARQL request contained in the given C<< $request >> object and return
a response object.
=cut
sub run {
my $self = shift;
my $req = shift;
try {
return $self->_run($req, @_);
}
catch (AtteanX::Endpoint::Error $e) {
my $resp = Plack::Response->new;
my $code = $e->code;
( run in 1.253 second using v1.01-cache-2.11-cpan-98e64b0badf )