Bugzilla – Attachment 77274 Details for
Bug 21116
Add API routes through plugins
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 21116: Add API routes through plugins
Bug-21116-Add-API-routes-through-plugins.patch (text/plain), 8.84 KB, created by
Tomás Cohen Arazi (tcohen)
on 2018-07-25 22:28:17 UTC
(
hide
)
Description:
Bug 21116: Add API routes through plugins
Filename:
MIME Type:
Creator:
Tomás Cohen Arazi (tcohen)
Created:
2018-07-25 22:28:17 UTC
Size:
8.84 KB
patch
obsolete
>From e8bebe8c11d5ebff44b20ae6a320504ff0c29e6c Mon Sep 17 00:00:00 2001 >From: Tomas Cohen Arazi <tomascohen@theke.io> >Date: Mon, 23 Jul 2018 11:14:47 -0300 >Subject: [PATCH] Bug 21116: Add API routes through plugins > >This patch adds plugins the capability of injecting new routes on the >API. > >The plugins should provide the following methods to be considered valid API-generating plugins: > >- 'api_routes': returning the 'path' component of the OpenAPI specification corresponding to the routes served by the plugin >- 'api_namespace': it should return a namespace to be used for grouping the endpoints provided by the plugin > >otherwise, they will be just skipped. > >All plugin-generated routes will be added the 'contrib' namespace, and >will end up placed inside /contrib/<namespace>, where <namespace> is what the 'api_namespace' returns. > >A sample endpoint will be added to the Kitchen Sink plugin, and tests >are being written. > >To test, wait a bit more for those samples :-D >--- > Koha/Exceptions/Plugin.pm | 84 +++++++++++++++++++ > Koha/REST/Plugin/PluginRoutes.pm | 140 +++++++++++++++++++++++++++++++ > Koha/REST/V1.pm | 37 ++++++-- > 3 files changed, 254 insertions(+), 7 deletions(-) > create mode 100644 Koha/Exceptions/Plugin.pm > create mode 100644 Koha/REST/Plugin/PluginRoutes.pm > >diff --git a/Koha/Exceptions/Plugin.pm b/Koha/Exceptions/Plugin.pm >new file mode 100644 >index 0000000000..534874484b >--- /dev/null >+++ b/Koha/Exceptions/Plugin.pm >@@ -0,0 +1,84 @@ >+package Koha::Exceptions::Plugin; >+ >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it under the >+# terms of the GNU General Public License as published by the Free Software >+# Foundation; either version 3 of the License, or (at your option) any later >+# version. >+# >+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY >+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR >+# A PARTICULAR PURPOSE. See the GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License along >+# with Koha; if not, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use Modern::Perl; >+ >+use Koha::Exceptions::Exception; >+ >+use Exception::Class ( >+ 'Koha::Exceptions::Plugin' => { >+ isa => 'Koha::Exceptions::Exception', >+ }, >+ 'Koha::Exceptions::Plugin::ForbiddenAction' => { >+ isa => 'Koha::Exceptions::Plugin', >+ description => 'The plugin is trying to do something it is not allowed to' >+ }, >+ 'Koha::Exceptions::Plugin::MissingMethod' => { >+ isa => 'Koha::Exceptions::Plugin', >+ description => 'Required method is missing', >+ fields => ['plugin_name','method'] >+ } >+); >+ >+sub full_message { >+ my $self = shift; >+ >+ my $msg = $self->message; >+ >+ unless ( $msg) { >+ if ( $self->isa('Koha::Exceptions::Plugin::MissingMethod') ) { >+ $msg = sprintf("Cannot use plugin (%s) because the it doesn't implement the '%s' method which is required.", $self->plugin_name, $self->method ); >+ } >+ } >+ >+ return $msg; >+} >+ >+=head1 NAME >+ >+Koha::Exceptions::Plugin - Base class for Plugin exceptions >+ >+=head1 Exceptions >+ >+=head2 Koha::Exceptions::Plugin >+ >+Generic Plugin exception >+ >+=head2 Koha::Exceptions::Plugin::MissingMethod >+ >+Exception to be used when a plugin is required to implement a specific >+method and it doesn't. >+ >+=head3 Parameters >+ >+=over >+ >+=item plugin_name: the plugin name for display purposes >+ >+=item method: the missing method >+ >+=back >+ >+=head1 Class methods >+ >+=head2 full_message >+ >+Overloaded method for exception stringifying. >+ >+=cut >+ >+1; >diff --git a/Koha/REST/Plugin/PluginRoutes.pm b/Koha/REST/Plugin/PluginRoutes.pm >new file mode 100644 >index 0000000000..67b7b11ebc >--- /dev/null >+++ b/Koha/REST/Plugin/PluginRoutes.pm >@@ -0,0 +1,140 @@ >+package Koha::REST::Plugin::PluginRoutes; >+ >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it under the >+# terms of the GNU General Public License as published by the Free Software >+# Foundation; either version 3 of the License, or (at your option) any later >+# version. >+# >+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY >+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR >+# A PARTICULAR PURPOSE. See the GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License along >+# with Koha; if not, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use Modern::Perl; >+ >+use Mojo::Base 'Mojolicious::Plugin'; >+ >+use Koha::Exceptions::Plugin; >+use Koha::Plugins; >+ >+use Clone qw(clone); >+use Try::Tiny; >+ >+=head1 NAME >+ >+Koha::REST::Plugin::PluginRoutes >+ >+=head1 API >+ >+=head2 Helper methods >+ >+=head3 register >+ >+=cut >+ >+sub register { >+ my ( $self, $app, $config ) = @_; >+ >+ my $spec = $config->{spec}; >+ my $validator = $config->{validator}; >+ >+ my @plugins; >+ >+ if ( C4::Context->preference('UseKohaPlugins') >+ && C4::Context->config("enable_plugins") ) >+ { >+ @plugins = Koha::Plugins->new()->GetPlugins( >+ { >+ method => 'api_routes', >+ } >+ ); >+ # plugin needs to define a namespace >+ @plugins = grep { $_->api_namespace } @plugins; >+ } >+ >+ foreach my $plugin ( @plugins ) { >+ $spec = inject_routes( $spec, $plugin, $validator ); >+ } >+ >+ $spec; >+} >+ >+=head3 inject_routes >+ >+=cut >+ >+sub inject_routes { >+ my ( $spec, $plugin, $validator ) = @_; >+ >+ return try { >+ >+ my $backup_spec = merge_spec(clone($spec), $plugin ); >+ if ( spec_ok( $backup_spec, $validator ) ) { >+ $spec = merge_spec( $spec, $plugin ); >+ } >+ else { >+ Koha::Exceptions::Plugin->throw( >+ "The resulting spec is invalid. Skipping " . $plugin->get_metadata->{name} >+ ); >+ } >+ >+ return $spec; >+ } >+ catch { >+ warn "$_"; >+ return $spec; >+ }; >+} >+ >+=head3 merge_spec >+ >+=cut >+ >+sub merge_spec { >+ my ( $spec, $plugin ) = @_; >+ >+ my $plugin_spec = $plugin->api_routes; >+ >+ foreach my $route ( keys %{ $plugin_spec } ) { >+ >+ my $THE_route = '/contrib/' . $plugin->api_namespace . $route; >+ if ( exists $spec->{ $THE_route } ) { >+ # Route exists, overwriting is forbidden >+ Koha::Exceptions::Plugin::ForbiddenAction->throw( >+ "Attempted to overwrite $THE_route" >+ ); >+ } >+ >+ $spec->{'paths'}->{ $THE_route } = $plugin_spec->{ $route }; >+ } >+ >+ return $spec; >+} >+ >+=head3 spec_ok >+ >+=cut >+ >+sub spec_ok { >+ my ( $spec, $validator ) = @_; >+ >+ return try { >+ $validator->load_and_validate_schema( >+ $spec, >+ { >+ allow_invalid_ref => 1, >+ } >+ ); >+ return 1; >+ } >+ catch { >+ return 0; >+ } >+} >+ >+1; >diff --git a/Koha/REST/V1.pm b/Koha/REST/V1.pm >index 57ad113291..2c9491150a 100644 >--- a/Koha/REST/V1.pm >+++ b/Koha/REST/V1.pm >@@ -20,6 +20,7 @@ use Modern::Perl; > use Mojo::Base 'Mojolicious'; > > use C4::Context; >+use JSON::Validator::OpenAPI::Mojolicious; > > =head1 NAME > >@@ -51,13 +52,35 @@ sub startup { > $self->secrets([$secret_passphrase]); > } > >- $self->plugin(OpenAPI => { >- url => $self->home->rel_file("api/v1/swagger/swagger.json"), >- route => $self->routes->under('/api/v1')->to('Auth#under'), >- allow_invalid_ref => 1, # required by our spec because $ref directly under >- # Paths-, Parameters-, Definitions- & Info-object >- # is not allowed by the OpenAPI specification. >- }); >+ my $validator = JSON::Validator::OpenAPI::Mojolicious->new; >+ $validator->load_and_validate_schema( >+ $self->home->rel_file("api/v1/swagger/swagger.json"), >+ { >+ allow_invalid_ref => 1, >+ } >+ ); >+ >+ push @{$self->routes->namespaces}, 'Koha::Plugin'; >+ >+ my $spec = $validator->schema->data; >+ $self->plugin( >+ 'Koha::REST::Plugin::PluginRoutes' => { >+ spec => $spec, >+ validator => $validator >+ } >+ ); >+ >+ $self->plugin( >+ OpenAPI => { >+ spec => $spec, >+ route => $self->routes->under('/api/v1')->to('Auth#under'), >+ allow_invalid_ref => >+ 1, # required by our spec because $ref directly under >+ # Paths-, Parameters-, Definitions- & Info-object >+ # is not allowed by the OpenAPI specification. >+ } >+ ); >+ > $self->plugin( 'Koha::REST::Plugin::Pagination' ); > $self->plugin( 'Koha::REST::Plugin::Query' ); > $self->plugin( 'Koha::REST::Plugin::Objects' ); >-- >2.18.0
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 21116
:
77274
|
77601
|
78194
|
78195
|
78322
|
78323
|
78542
|
78543