Bugzilla – Attachment 42086 Details for
Bug 13799
Add base for building RESTful API
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 13799: RESTful API with Mojolicious and Swagger2
Bug-13799-RESTful-API-with-Mojolicious-and-Swagger.patch (text/plain), 11.85 KB, created by
Alex Arnaud
on 2015-08-28 14:58:34 UTC
(
hide
)
Description:
Bug 13799: RESTful API with Mojolicious and Swagger2
Filename:
MIME Type:
Creator:
Alex Arnaud
Created:
2015-08-28 14:58:34 UTC
Size:
11.85 KB
patch
obsolete
>From e4ea1f236f418e736295b9a55807d1c37b0b240d Mon Sep 17 00:00:00 2001 >From: Julian Maurice <julian.maurice@biblibre.com> >Date: Wed, 4 Mar 2015 16:46:33 +0100 >Subject: [PATCH] Bug 13799: RESTful API with Mojolicious and Swagger2 > >Actual routes are: > /borrowers > Return a list of all borrowers in Koha > > /borrowers/{borrowernumber} > Return the borrower identified by {borrowernumber} > (eg. /borrowers/1) > >There is a test file you can run with: > $ prove t/db_dependent/rest/borrowers.t > >All API stuff is in /api/v1 (except Perl modules) >So we have: > /api/v1/script.cgi CGI script > /api/v1/swagger.json Swagger specification > >Change both OPAC and Intranet VirtualHosts to access the API, >so we have: > 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 > >Add a (disabled) virtual host in Apache configuration api.HOSTNAME, >so we have: > http://api.HOSTNAME/api/v1/swagger.json Swagger specification > http://api.HOSTNAME/api/v1/{path} API endpoint > >Add 'unblessed' subroutines to both Koha::Objects and Koha::Object to be >able to pass it to Mojolicious > >Test plan: > 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 > >Optionally, you could verify that http://(OPAC|INTRANET)/vX/borrowers >(where X is an integer greater than 1) returns a 404 error > >Signed-off-by: Alex Arnaud <alex.arnaud@biblibre.com> >--- > 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 > >diff --git a/C4/Installer/PerlDependencies.pm b/C4/Installer/PerlDependencies.pm >index f7a1bd9..0af33fd 100644 >--- a/C4/Installer/PerlDependencies.pm >+++ b/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; >diff --git a/Koha/Object.pm b/Koha/Object.pm >index a77eb5c..6e53461 100644 >--- a/Koha/Object.pm >+++ b/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 >diff --git a/Koha/Objects.pm b/Koha/Objects.pm >index 8ef6390..1ff91cb 100644 >--- a/Koha/Objects.pm >+++ b/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 >diff --git a/Koha/REST/V1.pm b/Koha/REST/V1.pm >new file mode 100644 >index 0000000..39cdab9 >--- /dev/null >+++ b/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; >diff --git a/Koha/REST/V1/Borrowers.pm b/Koha/REST/V1/Borrowers.pm >new file mode 100644 >index 0000000..b58ad2a >--- /dev/null >+++ b/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; >diff --git a/api/v1/app.pl b/api/v1/app.pl >new file mode 100755 >index 0000000..55ce87d >--- /dev/null >+++ b/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'); >diff --git a/api/v1/swagger.json b/api/v1/swagger.json >new file mode 100644 >index 0000000..9672f15 >--- /dev/null >+++ b/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" >+ } >+ } >+} >diff --git a/etc/koha-httpd.conf b/etc/koha-httpd.conf >index f9a1970..4f1fc47 100644 >--- a/etc/koha-httpd.conf >+++ b/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" >+ <Directory __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] >+ </Directory> > </IfModule> > </VirtualHost> > >@@ -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" >+ <Directory __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] >+ </Directory> > </IfModule> > </VirtualHost> >+ >+# Uncomment this VirtualHost to enable API access through >+# api.__WEBSERVER_HOST__:__WEBSERVER_PORT__ >+#<VirtualHost __WEBSERVER_IP__:__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 >+# >+# <IfModule mod_rewrite.c> >+# <Directory __INTRANET_CGI_DIR__/api> >+# 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] >+# </Directory> >+# </IfModule> >+#</VirtualHost> >diff --git a/t/db_dependent/api/v1/borrowers.t b/t/db_dependent/api/v1/borrowers.t >new file mode 100644 >index 0000000..43e5af0 >--- /dev/null >+++ b/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; >-- >1.7.10.4
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 13799
:
36700
|
36705
|
36938
|
36941
|
37119
|
37132
|
37172
|
38246
|
39156
|
39158
|
39159
|
39160
|
39161
|
39162
|
39163
|
39164
|
40088
|
40092
|
40093
|
40094
|
40098
|
40099
|
40101
|
40140
|
40141
|
40142
|
40463
|
40464
|
40465
|
40466
|
40467
|
40468
|
40469
|
40470
|
40471
|
40551
|
40552
|
40553
|
40554
|
40560
|
40561
|
40584
|
40585
|
40586
|
40587
|
40616
|
40617
|
40618
|
40619
|
41160
|
41161
|
41162
|
41268
|
41269
|
41270
|
41271
|
41272
|
41273
|
41274
|
41320
|
41321
|
41326
|
41327
|
41328
|
41329
|
41330
|
41331
|
41538
|
41539
|
41540
|
41541
|
41542
|
41543
|
41547
|
41554
|
42044
|
42085
|
42086
|
42123
|
42518
|
42766
|
42768
|
42801
|
42874
|
42875
|
42876
|
42877
|
42878
|
43186
|
43187
|
43189
|
43190
|
43191
|
43192
|
43204
|
43205
|
43206
|
43207
|
43208
|
43209
|
43210
|
43211
|
43212
|
43213
|
43214
|
43980
|
43981
|
43987
|
43989
|
43990
|
43991
|
43992
|
43993
|
43994
|
43995
|
43996
|
43997
|
43998
|
43999
|
44000
|
44001
|
44185
|
44285
|
44313
|
44375
|
44376
|
44377
|
44378
|
44379
|
44380
|
44381
|
44382
|
44383
|
44384
|
44385