From ee8cd72ef1e3250e9a761d288853b8220346620c Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Sun, 21 Oct 2018 19:12:06 +0100 Subject: [PATCH] basic Swagger spec support --- Build.PL | 1 + lib/App/Netdisco/Web.pm | 2 ++ lib/App/Netdisco/Web/AuthN.pm | 8 +++-- lib/App/Netdisco/Web/Plugin/API/Device.pm | 42 +++++++++++------------ lib/App/Netdisco/Web/Plugin/API/Node.pm | 16 ++++----- share/config.yml | 5 +++ 6 files changed, 42 insertions(+), 32 deletions(-) diff --git a/Build.PL b/Build.PL index bbba12a4..4bb9dd19 100644 --- a/Build.PL +++ b/Build.PL @@ -32,6 +32,7 @@ Module::Build->new( 'Dancer::Plugin::DBIC' => '0.2001', 'Dancer::Plugin::Auth::Extensible' => '0.30', 'Dancer::Plugin::Passphrase' => '2.0.1', + 'Dancer::Plugin::Swagger' => '0', 'Dancer::Session::Cookie' => '0.27', 'File::ShareDir' => '1.03', 'File::Slurper' => '0.009', diff --git a/lib/App/Netdisco/Web.pm b/lib/App/Netdisco/Web.pm index 901eee0d..c5c5b187 100644 --- a/lib/App/Netdisco/Web.pm +++ b/lib/App/Netdisco/Web.pm @@ -5,6 +5,7 @@ use Dancer::Plugin::Ajax; use Dancer::Plugin::DBIC; use Dancer::Plugin::Auth::Extensible; +use Dancer::Plugin::Swagger; use URI (); use Socket6 (); # to ensure dependency is met @@ -212,4 +213,5 @@ any qr{.*} => sub { }; } +swagger_auto_discover; true; diff --git a/lib/App/Netdisco/Web/AuthN.pm b/lib/App/Netdisco/Web/AuthN.pm index 7182fb28..7f6bfc2d 100644 --- a/lib/App/Netdisco/Web/AuthN.pm +++ b/lib/App/Netdisco/Web/AuthN.pm @@ -37,9 +37,11 @@ hook 'before' => sub { session(logged_in_user_realm => 'users'); } elsif (setting('api_token_lifetime') - and index(request->path,uri_for('/api/')->path) == 0) { + and (index(request->path,uri_for('/api/')->path) == 0 + or request->path eq uri_for('/swagger.json')->path)) { - my $user = $provider->validate_api_token(param('token')) + my $token = request->header('X-API-Key') || param('api_key'); + my $user = $provider->validate_api_token($token) or return; session(logged_in_user => $user); session(logged_in_user_realm => 'users'); @@ -102,7 +104,7 @@ post '/login' => sub { token => \'md5(random()::text)', })->discard_changes(); } - return 'token:'. $user->token; + return 'api_key:'. $user->token; } redirect param('return_url'); diff --git a/lib/App/Netdisco/Web/Plugin/API/Device.pm b/lib/App/Netdisco/Web/Plugin/API/Device.pm index 32c34e3e..dad14b2f 100644 --- a/lib/App/Netdisco/Web/Plugin/API/Device.pm +++ b/lib/App/Netdisco/Web/Plugin/API/Device.pm @@ -22,12 +22,12 @@ sub api_array_json { return (\@results); }; -ajax '/api/device/all' => require_login sub { +get '/api/device/all' => require_login sub { my @devices=schema('netdisco')->resultset('Device')->all; - return api_array_json(\@devices); + return to_json api_array_json(\@devices); }; -ajax '/api/device/search' => sub { +get '/api/device/search' => sub { my $para = params; my $search = {}; foreach my $param (keys %{$para}) { @@ -39,35 +39,35 @@ ajax '/api/device/search' => sub { try { @devices=schema('netdisco')->resultset('Device')->search($search); }; - return api_array_json(\@devices); + return to_json api_array_json(\@devices); }; -ajax '/api/device/:device' => require_login sub { +get '/api/device/:device' => require_login sub { my $dev = params->{device}; print "$dev\n"; my $device = schema('netdisco')->resultset('Device') ->search_for_device($dev) or send_error('Bad Device', 404); - return $device->{_column_data}; + return to_json $device->{_column_data}; }; -ajax '/api/device/:device/modules' => require_login sub { +get'/api/device/:device/modules' => require_login sub { my $dev = params->{device}; my $device = schema('netdisco')->resultset('Device') ->search_for_device($dev) or send_error('Bad Device', 404); my @modules = $device->modules; - return api_array_json(\@modules); + return to_json api_array_json(\@modules); }; -ajax '/api/device/:device/vlans' => require_login sub { +get '/api/device/:device/vlans' => require_login sub { my $dev = params->{device}; my $device = schema('netdisco')->resultset('Device') ->search_for_device($dev) or send_error('Bad Device', 404); my @vlans = $device->vlans; - return api_array_json(\@vlans); + return to_json api_array_json(\@vlans); }; -ajax '/api/device/:device/ports' => require_login sub { +get '/api/device/:device/ports' => require_login sub { my $dev = params->{device}; my $device = schema('netdisco')->resultset('Device') ->search_for_device($dev); @@ -88,34 +88,34 @@ ajax '/api/device/:device/ports' => require_login sub { $c->{vlans}=\@pvlans; push @results, $c; } - return \@results; + return to_json \@results; }; -ajax qr{/api/device/(?.*)/port/(?.*)/nodes$} => require_login sub { +get qr{/api/device/(?.*)/port/(?.*)/nodes$} => require_login sub { my $param = captures; my @ports = schema('netdisco')->resultset('Device') ->search_for_device($$param{ip})->ports->search({port => $$param{port}}); my @nodes = $ports[0]->nodes; - return api_array_json(\@nodes); + return to_json api_array_json(\@nodes); }; -ajax qr{/api/device/(?.*)/port/(?.*)/neighbor$} => require_login sub { +get qr{/api/device/(?.*)/port/(?.*)/neighbor$} => require_login sub { my $param = captures; my @ports = schema('netdisco')->resultset('Device') ->search_for_device($$param{ip})->ports->search({port => $$param{port}}); my @neighbors = $ports[0]->neighbor; - return api_array_json(\@neighbors); + return to_json api_array_json(\@neighbors); }; -ajax qr{/api/device/(?.*)/port/(?.*)/power$} => require_login sub { +get qr{/api/device/(?.*)/port/(?.*)/power$} => require_login sub { my $param = captures; my @ports = schema('netdisco')->resultset('Device') ->search_for_device($$param{ip})->ports->search({port => $$param{port}}); my @neighbors = $ports[0]->power; - return api_array_json(\@neighbors); + return to_json api_array_json(\@neighbors); }; -ajax qr{/api/device/(?.*)/port/(?.*)} => require_login sub { +get qr{/api/device/(?.*)/port/(?.*)} => require_login sub { my $param = captures; my $port; try { @@ -130,9 +130,9 @@ ajax qr{/api/device/(?.*)/port/(?.*)} => require_login sub { $port->{vlans} = \@pvlans; }; - return $port if defined $port; + return to_json $port if defined $port; status 404; - return { message => "Port not found" }; + return to_json { message => "Port not found" }; }; true; diff --git a/lib/App/Netdisco/Web/Plugin/API/Node.pm b/lib/App/Netdisco/Web/Plugin/API/Node.pm index ccb5a5a4..26aa0946 100644 --- a/lib/App/Netdisco/Web/Plugin/API/Node.pm +++ b/lib/App/Netdisco/Web/Plugin/API/Node.pm @@ -22,7 +22,7 @@ sub api_array_json { return (\@results); }; -ajax '/api/node/search' => require_login sub { +get '/api/node/search' => require_login sub { my $para = params; my $search = {}; # Generate a hashref of search terms. @@ -35,17 +35,17 @@ ajax '/api/node/search' => require_login sub { try { @ips = schema('netdisco')->resultset('Node')->search($search); }; - return api_array_json(\@ips); + return to_json api_array_json(\@ips); }; -ajax '/api/node/:node/:method' => require_login sub { +get '/api/node/:node/:method' => require_login sub { my $node = params->{node}; my $method = params->{method}; # Make sure $node is actually a mac address in the proper format. # TODO change to NetAddr::MAC if (!($node =~ m/([0-9a-f]{2}:){5}([0-9a-f]{2})/)){ status 400; - return ({ error => "Not a MAC Address. Address must follow the format aa:bb:cc:dd:ee:ff." }); + return to_json { error => "Not a MAC Address. Address must follow the format aa:bb:cc:dd:ee:ff." }; } try { my @nodesearch = schema('netdisco')->resultset('Node')->search({ mac => $node}); @@ -56,20 +56,20 @@ ajax '/api/node/:node/:method' => require_login sub { # Dancer's JSON serializer doesn't like the objects if (ref($node) =~ m/ResultSet/) { my @nodes = $node->all; - return api_array_json(\@nodes); + return to_json api_array_json(\@nodes); } else { my $nodes = $node; - return $nodes->{_column_data}; + return to_json $nodes->{_column_data}; } } catch { my ($exception) = @_; if ($exception =~ m/Can\'t call method "$method" on an undefined value/) { status 404; - return ({ error => "MAC Address not found."}); + return to_json { error => "MAC Address not found."}; } status 400; - return ({ error => "Invalid collection $method." }); + return to_json { error => "Invalid collection $method." }; }; }; diff --git a/share/config.yml b/share/config.yml index 548b69f2..4e2fe013 100644 --- a/share/config.yml +++ b/share/config.yml @@ -479,6 +479,11 @@ engines: INCLUDE_PATH: [] layout: 'main' plugins: +plugins: + Swagger: + main_api_module: 'App::Netdisco' + auto_discover_skip: + - qr#^/(?!api/)\w+# Auth::Extensible: no_api_change_warning: true no_default_pages: true