@@ -, +, @@
Swagger2
/borrowers
Return a list of all borrowers in Koha
/borrowers/{borrowernumber}
Return the borrower identified by {borrowernumber}
(eg. /borrowers/1)
$ prove t/db_dependent/rest/borrowers.t
/api/v1/script.cgi CGI script
/api/v1/swagger.json Swagger specification
http://OPAC/api/v1/swagger.json Swagger specification
http://OPAC/api/v1/{path} API endpoint
http://INTRANET/api/v1/swagger.json Swagger specification
http://INTRANET/api/v1/{path} API endpoint
http://api.HOSTNAME/api/v1/swagger.json Swagger specification
http://api.HOSTNAME/api/v1/{path} API endpoint
1/ Install Perl modules Mojolicious and Swagger2
2/ perl Makefile.PL
3/ make && make install
4/ Change etc/koha-httpd.conf and copy it to the right place if needed
5/ Reload Apache
6/ Check that http://(OPAC|INTRANET)/api/v1/borrowers and
http://(OPAC|INTRANET)/api/v1/borrowers/{borrowernumber} works
---
C4/Installer/PerlDependencies.pm | 10 ++++
Koha/Object.pm | 12 +++++
Koha/Objects.pm | 12 +++++
Koha/REST/V1.pm | 28 ++++++++++
Koha/REST/V1/Borrowers.pm | 29 ++++++++++
api/v1/app.pl | 6 +++
api/v1/swagger.json | 108 ++++++++++++++++++++++++++++++++++++++
etc/koha-httpd.conf | 56 ++++++++++++++++++++
t/db_dependent/api/v1/borrowers.t | 37 +++++++++++++
9 files changed, 298 insertions(+)
create mode 100644 Koha/REST/V1.pm
create mode 100644 Koha/REST/V1/Borrowers.pm
create mode 100755 api/v1/app.pl
create mode 100644 api/v1/swagger.json
create mode 100644 t/db_dependent/api/v1/borrowers.t
--- a/C4/Installer/PerlDependencies.pm
+++ a/C4/Installer/PerlDependencies.pm
@@ -767,6 +767,16 @@ our $PERL_DEPS = {
'required' => '0',
'min_ver' => '0.614',
},
+ 'Mojolicious' => {
+ 'usage' => 'REST API',
+ 'required' => '0',
+ 'min_ver' => '5.54',
+ },
+ 'Swagger2' => {
+ 'usage' => 'REST API',
+ 'required' => '0',
+ 'min_ver' => '0.28',
+ },
};
1;
--- a/Koha/Object.pm
+++ a/Koha/Object.pm
@@ -207,6 +207,18 @@ sub id {
return $id;
}
+=head3 $object->unblessed();
+
+Returns an unblessed representation of object.
+
+=cut
+
+sub unblessed {
+ my ($self) = @_;
+
+ return { $self->_result->get_columns };
+}
+
=head3 $object->_result();
Returns the internal DBIC Row object
--- a/Koha/Objects.pm
+++ a/Koha/Objects.pm
@@ -181,6 +181,18 @@ sub as_list {
return wantarray ? @objects : \@objects;
}
+=head3 Koha::Objects->unblessed
+
+Returns an unblessed representation of objects.
+
+=cut
+
+sub unblessed {
+ my ($self) = @_;
+
+ return [ map { $_->unblessed } $self->as_list ];
+}
+
=head3 Koha::Objects->_wrap
wraps the DBIC object in a corresponding Koha object
--- a/Koha/REST/V1.pm
+++ a/Koha/REST/V1.pm
@@ -0,0 +1,28 @@
+package Koha::REST::V1;
+
+use Modern::Perl;
+use Mojo::Base 'Mojolicious';
+
+sub startup {
+ my $self = shift;
+
+ my $route = $self->routes->under->to(
+ cb => sub {
+ my $c = shift;
+ my $user = $c->param('user');
+ # Do the authentication stuff here...
+ $c->stash('user', $user);
+ return 1;
+ }
+ );
+
+ # Force charset=utf8 in Content-Type header for JSON responses
+ $self->types->type(json => 'application/json; charset=utf8');
+
+ $self->plugin(Swagger2 => {
+ route => $route,
+ url => $self->home->rel_file("api/v1/swagger.json"),
+ });
+}
+
+1;
--- a/Koha/REST/V1/Borrowers.pm
+++ a/Koha/REST/V1/Borrowers.pm
@@ -0,0 +1,29 @@
+package Koha::REST::V1::Borrowers;
+
+use Modern::Perl;
+
+use Mojo::Base 'Mojolicious::Controller';
+
+use Koha::Borrowers;
+
+sub list_borrowers {
+ my ($c, $args, $cb) = @_;
+
+ my $borrowers = Koha::Borrowers->search;
+
+ $c->$cb($borrowers->unblessed, 200);
+}
+
+sub get_borrower {
+ my ($c, $args, $cb) = @_;
+
+ my $borrower = Koha::Borrowers->find($args->{borrowernumber});
+
+ if ($borrower) {
+ return $c->$cb($borrower->unblessed, 200);
+ }
+
+ $c->$cb({error => "Borrower not found"}, 404);
+}
+
+1;
--- a/api/v1/app.pl
+++ a/api/v1/app.pl
@@ -0,0 +1,6 @@
+#!/usr/bin/env perl
+
+use Modern::Perl;
+
+require Mojolicious::Commands;
+Mojolicious::Commands->start_app('Koha::REST::V1');
--- a/api/v1/swagger.json
+++ a/api/v1/swagger.json
@@ -0,0 +1,108 @@
+{
+ "swagger": "2.0",
+ "info": {
+ "title": "Koha REST API",
+ "version": "1",
+ "license": {
+ "name": "GPL v3",
+ "url": "http://www.gnu.org/licenses/gpl.txt"
+ },
+ "contact": {
+ "name": "Koha Team",
+ "url": "http://koha-community.org/"
+ }
+ },
+ "basePath": "/api/v1",
+ "paths": {
+ "/borrowers": {
+ "get": {
+ "x-mojo-controller": "Koha::REST::V1::Borrowers",
+ "operationId": "listBorrowers",
+ "tags": ["borrowers"],
+ "produces": [
+ "application/json"
+ ],
+ "responses": {
+ "200": {
+ "description": "A list of borrowers",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/borrower"
+ }
+ }
+ }
+ }
+ }
+ },
+ "/borrowers/{borrowernumber}": {
+ "get": {
+ "x-mojo-controller": "Koha::REST::V1::Borrowers",
+ "operationId": "getBorrower",
+ "tags": ["borrowers"],
+ "parameters": [
+ {
+ "$ref": "#/parameters/borrowernumberPathParam"
+ }
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "responses": {
+ "200": {
+ "description": "A borrower",
+ "schema": {
+ "$ref": "#/definitions/borrower"
+ }
+ },
+ "404": {
+ "description": "Borrower not found",
+ "schema": {
+ "$ref": "#/definitions/error"
+ }
+ }
+ }
+ }
+ }
+ },
+ "definitions": {
+ "borrower": {
+ "type": "object",
+ "properties": {
+ "borrowernumber": {
+ "$ref": "#/definitions/borrowernumber"
+ },
+ "cardnumber": {
+ "description": "library assigned ID number for borrowers"
+ },
+ "surname": {
+ "description": "borrower's last name"
+ },
+ "firstname": {
+ "description": "borrower's first name"
+ }
+ }
+ },
+ "borrowernumber": {
+ "description": "Borrower internal identifier"
+ },
+ "error": {
+ "type": "object",
+ "properties": {
+ "error": {
+ "description": "Error message",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "parameters": {
+ "borrowernumberPathParam": {
+ "name": "borrowernumber",
+ "in": "path",
+ "description": "Internal borrower identifier",
+ "required": "true",
+ "type": "integer"
+ }
+ }
+}
--- a/etc/koha-httpd.conf
+++ a/etc/koha-httpd.conf
@@ -112,6 +112,20 @@
RewriteRule ^/bib/([^\/]*)/?$ /cgi-bin/koha/opac-detail\.pl?bib=$1 [PT]
RewriteRule ^/isbn/([^\/]*)/?$ /search?q=isbn:$1 [PT]
RewriteRule ^/issn/([^\/]*)/?$ /search?q=issn:$1 [PT]
+
+ # REST API configuration
+ Alias "/api" "__OPAC_CGI_DIR__/api"
+
+ Options +ExecCGI +FollowSymlinks
+ AddHandler cgi-script .pl
+
+ RewriteEngine On
+ RewriteBase /api/
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteCond %{REQUEST_FILENAME} !-d
+ RewriteCond %{DOCUMENT_ROOT}/../api/$1/app.pl -f
+ RewriteRule ^(.*?)/.* $1/app.pl/api/$0 [L]
+
@@ -214,5 +228,47 @@
RewriteRule ^/bib/([^\/]*)/?$ /cgi-bin/koha/detail\.pl?bib=$1 [PT]
RewriteRule ^/isbn/([^\/]*)/?$ /search?q=isbn:$1 [PT]
RewriteRule ^/issn/([^\/]*)/?$ /search?q=issn:$1 [PT]
+
+
+ # REST API configuration
+ Alias "/api" "__INTRANET_CGI_DIR__/api"
+
+ Options +ExecCGI +FollowSymlinks
+ AddHandler cgi-script .pl
+
+ RewriteEngine On
+ RewriteBase /api/
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteCond %{REQUEST_FILENAME} !-d
+ RewriteCond %{DOCUMENT_ROOT}/../api/$1/app.pl -f
+ RewriteRule ^(.*?)/.* $1/app.pl/api/$0 [L]
+
+
+# Uncomment this VirtualHost to enable API access through
+# api.__WEBSERVER_HOST__:__WEBSERVER_PORT__
+#
+# ServerAdmin __WEBMASTER_EMAIL__
+# DocumentRoot __INTRANET_CGI_DIR__/api
+# ServerName api.__WEBSERVER_HOST__:__WEBSERVER_PORT__
+# SetEnv KOHA_CONF "__KOHA_CONF_DIR__/koha-conf.xml"
+# SetEnv PERL5LIB "__PERL_MODULE_DIR__"
+# ErrorLog __LOG_DIR__/koha-api-error_log
+#
+#
+#
+# Options +ExecCGI +FollowSymlinks
+# AddHandler cgi-script .pl
+#
+# RewriteEngine on
+#
+# RewriteRule ^api/(.*) $1 [L]
+#
+# RewriteCond %{REQUEST_FILENAME} !-f
+# RewriteCond %{REQUEST_FILENAME} !-d
+# RewriteCond %{DOCUMENT_ROOT}/$1/app.pl -f
+# RewriteRule ^(.*?)/.* $1/app.pl/api/$0 [L]
+#
+#
+#
--- a/t/db_dependent/api/v1/borrowers.t
+++ a/t/db_dependent/api/v1/borrowers.t
@@ -0,0 +1,37 @@
+#!/usr/bin/env perl
+
+use Modern::Perl;
+
+use Test::More tests => 6;
+use Test::Mojo;
+
+use C4::Context;
+
+use Koha::Database;
+use Koha::Borrower;
+
+my $dbh = C4::Context->dbh;
+$dbh->{AutoCommit} = 0;
+$dbh->{RaiseError} = 1;
+
+my $t = Test::Mojo->new('Koha::REST::V1');
+
+my $categorycode = Koha::Database->new()->schema()->resultset('Category')->first()->categorycode();
+my $branchcode = Koha::Database->new()->schema()->resultset('Branch')->first()->branchcode();
+
+my $borrower = Koha::Borrower->new;
+$borrower->categorycode( $categorycode );
+$borrower->branchcode( $branchcode );
+$borrower->surname("Test Surname");
+$borrower->store;
+my $borrowernumber = $borrower->borrowernumber;
+
+$t->get_ok('/api/v1/borrowers')
+ ->status_is(200);
+
+$t->get_ok("/api/v1/borrowers/$borrowernumber")
+ ->status_is(200)
+ ->json_is('/borrowernumber' => $borrowernumber)
+ ->json_is('/surname' => "Test Surname");
+
+$dbh->rollback;
--