CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
How to write simple API for my cgi script?

 



Master_Sergius
Novice

Aug 12, 2018, 2:02 AM

Post #1 of 5 (2173 views)
How to write simple API for my cgi script? Can't Post

Hello, Perl community! I'm new in Perl world and as far as I can see - there are a lot of ways to code something in Perl.
I have cgi script, which looks up for word forms in database with simple UI (yes, it's not pretty):


Code
#!/usr/bin/perl -w 

use strict;
use warnings;
use CGI qw(:standard);
use utf8;
use Encode;

use Database;

my $cgi = CGI->new();
print $cgi->header(-charset => 'utf-8'),
$cgi->start_html(-title => 'Word finder app', -encoding => 'utf8');

my $ENV;

my $uri = $cgi->path_info;
print "uri: $uri";

$ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/;
if ($ENV{'REQUEST_METHOD'} eq "POST") {
my $word = param('word_input');
my $res;
if (param('word_part')) {
$res = get_words($word);
} elsif (param('word_form')) {
$res = get_word_form($word);
};
draw_page($res);
} else {
draw_page();
}

sub draw_page {
my $res = shift;
print '<div style="float:left; width:100%">';
my $input_form = div({-align => 'center'},
h3('Enter word or part of word'),
start_form(-action => '/cgi-bin/words_cgi.pl',
-method => 'post',
-name => 'form_word_input',
-id => 'form_word_input'),
textfield(-name => 'word_input',
-id => 'word_input'),
br,
submit(-name => 'word_part',
-form => 'form_word_input',
-value => 'find all words'),
submit(-name => 'word_form',
-form => 'form_word_input',
-value => 'find main form'),
end_form);
print div({-style => 'float: left; width: 70%'}, $input_form);

my $dbh = new Database();
my $history_records = '';
foreach my $key (keys $dbh->get_cache()) {
$history_records .= "$key<br/>";
}

my $history_div = div({-align => 'center'},
h5('History of queries'),
$history_records);
print div({-style => 'float: right; width: 30%'}, $history_div);

print '</div>';
print '<div style="float:left;">';
if ($res) {
print '<table cellspacing="2" border="1" cellpadding="5">';
foreach my $word_res (@{$res}) {
print "<tr><td>$word_res</td></tr>";
};
print '</table>';
}
print '</div>';
};

sub get_words {
my $word_part = shift;
my $limit = 10;
my $dbh = new Database();
$dbh->connect('perl_crud');
my $res = $dbh->select_data('SELECT uw_form FROM ua_wf
WHERE uw_form LIKE ? LIMIT ?',
['%'.$word_part.'%', $limit]);

$dbh->disconnect();
return $res;
};

sub get_word_form {
my $word = shift;
my $dbh = new Database();
$dbh->connect('perl_crud');
my $res = $dbh->select_data('SELECT ut_root FROM ua_root WHERE ut_id IN
(SELECT uw_ut_id FROM ua_wf WHERE uw_form = ?)',
[$word]);
$dbh->disconnect();
return $res;
};


exit(0);


Now I want to write simple API to use this script in console or other script. For example if I type: <host>/v1/get_words?word=<some_word>, I should get response in JSON format.
What I should use here? How to add this to my script properly?
I can use $cgi->path_info, or CGI::Application::Dispatch, or some REST framework or something else??? And how?


Update #1
Well, I did this variant, it works. But, I'm sure, it's not the best:


Code
#!/usr/bin/perl -w 

use strict;

use CGI qw(:standard);
use Encode;
use JSON;
use utf8;

use Database;

my $cgi = CGI->new();

sub draw_page {
my $res = shift;
print '<div style="float:left; width:100%">';
my $input_form = div({-align => 'center'},
h3('Enter word or part of word'),
start_form(-action => '/cgi-bin/words_cgi.pl',
-method => 'post',
-name => 'form_word_input',
-id => 'form_word_input'),
textfield(-name => 'word_input',
-id => 'word_input'),
br,
submit(-name => 'word_part',
-form => 'form_word_input',
-value => 'find all words'),
submit(-name => 'word_form',
-form => 'form_word_input',
-value => 'find main form'),
end_form);
print div({-style => 'float: left; width: 70%'}, $input_form);

my $dbh = new Database();
my $history_records = '';
foreach my $key (keys $dbh->get_cache()) {
$history_records .= "$key<br/>";
}

my $history_div = div({-align => 'center'},
h5('History of queries'),
$history_records);
print div({-style => 'float: right; width: 30%'}, $history_div);

print '</div>';
print '<div style="float:left;">';
if ($res) {
print '<table cellspacing="2" border="1" cellpadding="5">';
foreach my $word_res (@{$res}) {
print "<tr><td>$word_res</td></tr>";
};
print '</table>';
}
print '</div>';
};


sub get_words {
my $word_part = shift;
my $limit = 10;
my $dbh = new Database();
$dbh->connect('perl_crud');
my $res = $dbh->select_data('SELECT uw_form FROM ua_wf
WHERE uw_form LIKE ? LIMIT ?',
['%'.$word_part.'%', $limit]);

$dbh->disconnect();
return $res;
};


sub get_word_form {
my $word = shift;
my $dbh = new Database();
$dbh->connect('perl_crud');
my $res = $dbh->select_data('SELECT ut_root FROM ua_root WHERE ut_id IN
(SELECT uw_ut_id FROM ua_wf WHERE uw_form = ?)',
[$word]);
$dbh->disconnect();
return $res;
};


sub check_api_call {
my %api_endpoints = (
'/v1/words/get_all_words' => sub { my $word = shift; return {'data' => get_words($word)} },
'/v1/words/get_root_form' => sub { my $word = shift; return {'data' => get_word_form($word)} },
'error' => sub { return {'error' => 'uknown api endpoint'} }
);
my $uri = $cgi->path_info;
if ($uri) {
my $word = param('word_input');
my $api_method = $api_endpoints{$uri} || $api_endpoints{'error'};
my $res = $api_method->($word);
return encode_json($res);
}
}

sub main {

my $res = check_api_call();
if ($res) {
print $cgi->header('application/json');
print $res;
} else {
print $cgi->header(-charset => 'utf-8'),
$cgi->start_html(-title => 'Word finder app', -encoding => 'utf8');
my $ENV;
$ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/;
if ($ENV{'REQUEST_METHOD'} eq "POST") {
my $word = param('word_input');
my $res;
if (param('word_part')) {
$res = get_words($word);
} elsif (param('word_form')) {
$res = get_word_form($word);
};
draw_page($res);
} else {
draw_page();
}
};
};


main();

exit(0);



(This post was edited by Master_Sergius on Aug 12, 2018, 8:41 AM)


BillKSmith
Veteran

Aug 12, 2018, 3:38 PM

Post #2 of 5 (2160 views)
Re: [Master_Sergius] How to write simple API for my cgi script? [In reply to] Can't Post

You are right, there are a lot of ways to code in Perl. In fact, most Perl programmers are proud of what they call "TIMTOWTDI" ("There is more than one way to do it").

I know that the CGI module is considered obsolete, and discouraged in new code. I am not familiar with newer replacements.

You have one minor error that suggests that you may have a serious lack of understanding of Perl data types. You declare the scalar $ENV as a lexical variable and never use it. The hash %ENV (which you do use) is a special (built-in) variable. You can access perl's own documentation for it by typing at the command line:

Code
perldoc perlvar


Other than that, your code looks good.
Good Luck,
Bill


Master_Sergius
Novice

Aug 13, 2018, 11:34 AM

Post #3 of 5 (2152 views)
Re: [BillKSmith] How to write simple API for my cgi script? [In reply to] Can't Post

Thank you. Your answer is really helpful.


Zhris
Enthusiast

Aug 19, 2018, 8:31 AM

Post #4 of 5 (2106 views)
Re: [Master_Sergius] How to write simple API for my cgi script? [In reply to] Can't Post

Hi,


Quote
Now I want to write simple API to use this script in console or other script. For example if I type: <host>/v1/get_words?word=<some_word>, I should get response in JSON format.
What I should use here?


With your first script, most simply, you could handle both GET and POST request methods, and add a new query parameter "json", which if true serializes the response data structure as json instead of html. But from your second script it looks as though you have handled this in your own way.


Quote
How to add this to my script properly? I can use $cgi->path_info, or CGI::Application::Dispatch, or some REST framework or something else??? And how?


As you are aware, CGI is outdated and basically deprecated. I recommend using a modern web application framework, one of what I call, "the big three", Dancer2, Mojolicious or Catalyst. There are others available such as CGI::Application::Dispatch that you mentioned, but those I listed are featuresome and there is much more support.

I recommend starting with Dancer2, its simpler to learn than the others. Its focus is specifically on interfacing the typically low level side of things, but there are various core engines that handle common components such as sessions and templates, and plugins that extend its functionality such as for form and database management.

In my opinion, to do it properly, you would need to look into the following (or equivalents), in order to replace your current application:

- Dancer2
- Template(::Toolkit) via Dancer2::Template::TemplateToolkit
- DBI via Dancer2::Plugin::Database
- HTML::FormHandler

And maybe:

- DBIx::Class via Dancer2::Plugin::DBIC

Chris


(This post was edited by Zhris on Aug 19, 2018, 8:36 AM)


Master_Sergius
Novice

Aug 20, 2018, 12:17 AM

Post #5 of 5 (2088 views)
Re: [Zhris] How to write simple API for my cgi script? [In reply to] Can't Post

Great! Thank you!

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives