Should Perl talk to Rails via LWP

Hi folks,

I need your opinions on a basic design issue.

I’ve seen the light of RoR and have replaced my Perl (DBI/CGI) based web
server <-> RDBMS communication with RoR, but I still have a whole host
of users (other servers/OS’s etc) out there wanting to talk to my
RDBMS and they only talk Perl. Also they don’t want to talk Perl/DBI
directly (they are not allowed to connect to the RDBMS directly). What
I did in the “old” days was to provide, through Perl modules on the
servers out there, a very simple hash based interface for my users.

Using their own Perl and my modules they could populated hashes with
data bound for the RDBMS and send them to my “proxy server” (the web
server with all the Perl/DBI/CGI). Similarly the data they got back
from the RDBMS (via the “proxy”) was a hash.

The whole thing is very simplistic and not very robust on error
handling.

Now that I’ve got a Rails to make my life a lot more fun I’m wondering
how to allow the same simple communication.

I could hack another LWP (what I used with the “old” solution)
solution and let them “fill in forms” created by RoR, but this can not
possibly be the best solution! I know very little about XMLProxy and
am not sure that this the best way to go. Forcing everyone to
abandon Perl and use Ruby is also out of the question.

Any ideas on what might be the best way to provide my users with what
they are used to and keep my newfound love, RoR?

Bealach

What your users need is a Web Service. Lucky for you, rails has
ActionWebService to make your life easier! Once you get a web
service up and running, your users can use a variety of perl modules
to access your data, including SOAP::Lite. You get to focus on your
application - let someone else mess with the perl modules.

And the best part is … with a web service up and running, your
users don’t HAVE to use perl. They could use anything! Ruby!
Java! Perl! even PHP! It doesn’t matter to you cuz you’re using a
standards compliant web service!

I know you’re smiling right now. And you should be. LIfe just got
good.

Unfortunately I haven’t the time to explain everything. If you have
the Agile Web Programming book, you’re good to go - check out chapter
20. Otherwise, try googling rails ActionWebService. Or perhaps this
link will be enlightening: Peak Obsession

-Derrick S.

Ditto on the web services thing. That’s really what web services are
for, you expose your API via XML, and then your users can decide for
themselves what language they want to handle the XML in. Perl has tons
of strong XML tools so your users will be totally happy, and although
XML for web services tends to be rather verbose, it’s actually very
simple and very powerful. I haven’t played with AWS but from first
glance it looks very capable.


Giles B.
http://www.gilesgoatboy.org

On Mon, 17 Apr 2006, Giles B. wrote:

Ditto on the web services thing. That’s really what web services are
for, you expose your API via XML, and then your users can decide for
themselves what language they want to handle the XML in. Perl has tons
of strong XML tools so your users will be totally happy, and although
XML for web services tends to be rather verbose, it’s actually very
simple and very powerful. I haven’t played with AWS but from first
glance it looks very capable.

I just moved an application from Perl Client/Perl Server (XMLRPC::Lite)
to
Perl Client, AWS Server. The only real issue I ran across was stricter
data typing and how I was delivering the results (Hash references vs.
Arrays). But it was a pretty smooth transition, and my Perl client
isn’t
having any problems at all talking to AWS.

–Wade

Thanks for your comments guys. Looks like I’ve some homework to do
before I can bug you again :slight_smile:

Bealach

I’m feeling particularly stupid now! I’ve followed the discussion in
section 20.2 of the Agile Web Dev book, but can not get it to run.

Somebody please tell me that I’m having an attack of dyslexia and that
this is easy to fix!

Here are my app/apis/product_api.rb and
app/controllers/backend_controller.rb

class ProductApi < ActionWebService::API::Base
api_method :find_all_products,
:returns => [[:int]]
api_method :find_product_by_id,
:expects => [:int],
:returns => [Product]
end

class BackendController < ApplicationController
wsdl_service_name ‘Backend’
web_service_api ProductApi
web_service_scaffold :invoke
def find_all_products
Product.find(:all).map{ |product| product.id }
end

def find_product_by_id(id)
Product.find(id)
end
end

And I end up with the following error:

------------------ERROR-----------------
NameError in #

neither BackendApi or BackendAPI found

RAILS_ROOT: script/…/config/…
Application Trace | Framework Trace | Full Trace

/usr/lib/ruby/gems/1.8/gems/actionwebservice-1.1.0/lib/action_web_service/container/action_controller_container.rb:76:in
require_web_service_api' /usr/lib/ruby/gems/1.8/gems/actionwebservice-1.1.0/lib/action_web_service/container/action_controller_container.rb:50:inweb_service_api’
/usr/lib/ruby/gems/1.8/gems/actionwebservice-1.1.0/lib/action_web_service/container/action_controller_container.rb:87:in
inherited_without_action_controller' /usr/lib/ruby/gems/1.8/gems/actionwebservice-1.1.0/lib/action_web_service/dispatcher/action_controller_dispatcher.rb:34:ininherited’
#{RAILS_ROOT}/app/controllers/backend_controller.rb:1
generated/routing/recognition.rb:3:in eval' generated/routing/recognition.rb:3:inrecognize_path’

/usr/lib/ruby/gems/1.8/gems/actionwebservice-1.1.0/lib/action_web_service/container/action_controller_container.rb:76:in
require_web_service_api' /usr/lib/ruby/gems/1.8/gems/actionwebservice-1.1.0/lib/action_web_service/container/action_controller_container.rb:50:inweb_service_api’
/usr/lib/ruby/gems/1.8/gems/actionwebservice-1.1.0/lib/action_web_service/container/action_controller_container.rb:87:in
inherited_without_action_controller' /usr/lib/ruby/gems/1.8/gems/actionwebservice-1.1.0/lib/action_web_service/dispatcher/action_controller_dispatcher.rb:34:ininherited’
/usr/lib/ruby/gems/1.8/gems/activesupport-1.3.0/lib/active_support/dependencies.rb:129:in
load' /usr/lib/ruby/gems/1.8/gems/activesupport-1.3.0/lib/active_support/dependencies.rb:56:inrequire_or_load’
/usr/lib/ruby/gems/1.8/gems/activesupport-1.3.0/lib/active_support/dependencies.rb:30:in
depend_on' /usr/lib/ruby/gems/1.8/gems/activesupport-1.3.0/lib/active_support/dependencies.rb:74:inrequire_dependency’
/usr/lib/ruby/gems/1.8/gems/activesupport-1.3.0/lib/active_support/dependencies.rb:87:in
const_missing' /usr/lib/ruby/gems/1.8/gems/activesupport-1.3.0/lib/active_support/dependencies.rb:120:inconst_missing’
/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.0/lib/action_controller/routing.rb:237:in
traverse_to_controller' /usr/lib/ruby/gems/1.8/gems/actionpack-1.12.0/lib/action_controller/routing.rb:237:intraverse_to_controller’
/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.0/lib/action_controller/routing.rb:477:in
recognize!' /usr/lib/ruby/gems/1.8/gems/rails-1.1.0/lib/dispatcher.rb:38:indispatch’
/usr/lib/ruby/gems/1.8/gems/rails-1.1.0/lib/webrick_server.rb:115:in
handle_dispatch' /usr/lib/ruby/gems/1.8/gems/rails-1.1.0/lib/webrick_server.rb:81:inservice’
/usr/lib/ruby/1.8/webrick/httpserver.rb:104:in service' /usr/lib/ruby/1.8/webrick/httpserver.rb:65:inrun’
/usr/lib/ruby/1.8/webrick/server.rb:173:in start_thread' /usr/lib/ruby/1.8/webrick/server.rb:162:instart_thread’
/usr/lib/ruby/1.8/webrick/server.rb:95:in start' /usr/lib/ruby/1.8/webrick/server.rb:92:instart’
/usr/lib/ruby/1.8/webrick/server.rb:23:in start' /usr/lib/ruby/1.8/webrick/server.rb:82:instart’
/usr/lib/ruby/gems/1.8/gems/rails-1.1.0/lib/webrick_server.rb:67:in
dispatch' /usr/lib/ruby/gems/1.8/gems/rails-1.1.0/lib/commands/servers/webrick.rb:59 /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:21:inrequire’
/usr/lib/ruby/gems/1.8/gems/activesupport-1.3.0/lib/active_support/dependencies.rb:136:in
require' /usr/lib/ruby/gems/1.8/gems/rails-1.1.0/lib/commands/server.rb:30 /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:21:inrequire’
/usr/lib/ruby/gems/1.8/gems/activesupport-1.3.0/lib/active_support/dependencies.rb:136:in
`require’
script/server:3

/usr/lib/ruby/gems/1.8/gems/actionwebservice-1.1.0/lib/action_web_service/container/action_controller_container.rb:76:in
require_web_service_api' /usr/lib/ruby/gems/1.8/gems/actionwebservice-1.1.0/lib/action_web_service/container/action_controller_container.rb:50:inweb_service_api’
/usr/lib/ruby/gems/1.8/gems/actionwebservice-1.1.0/lib/action_web_service/container/action_controller_container.rb:87:in
inherited_without_action_controller' /usr/lib/ruby/gems/1.8/gems/actionwebservice-1.1.0/lib/action_web_service/dispatcher/action_controller_dispatcher.rb:34:ininherited’
#{RAILS_ROOT}/app/controllers/backend_controller.rb:1
/usr/lib/ruby/gems/1.8/gems/activesupport-1.3.0/lib/active_support/dependencies.rb:129:in
load' /usr/lib/ruby/gems/1.8/gems/activesupport-1.3.0/lib/active_support/dependencies.rb:56:inrequire_or_load’
/usr/lib/ruby/gems/1.8/gems/activesupport-1.3.0/lib/active_support/dependencies.rb:30:in
depend_on' /usr/lib/ruby/gems/1.8/gems/activesupport-1.3.0/lib/active_support/dependencies.rb:74:inrequire_dependency’
/usr/lib/ruby/gems/1.8/gems/activesupport-1.3.0/lib/active_support/dependencies.rb:87:in
const_missing' /usr/lib/ruby/gems/1.8/gems/activesupport-1.3.0/lib/active_support/dependencies.rb:120:inconst_missing’
/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.0/lib/action_controller/routing.rb:237:in
traverse_to_controller' generated/routing/recognition.rb:3:ineval’
/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.0/lib/action_controller/routing.rb:237:in
traverse_to_controller' generated/routing/recognition.rb:3:inrecognize_path’
/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.0/lib/action_controller/routing.rb:477:in
recognize!' /usr/lib/ruby/gems/1.8/gems/rails-1.1.0/lib/dispatcher.rb:38:indispatch’
/usr/lib/ruby/gems/1.8/gems/rails-1.1.0/lib/webrick_server.rb:115:in
handle_dispatch' /usr/lib/ruby/gems/1.8/gems/rails-1.1.0/lib/webrick_server.rb:81:inservice’
/usr/lib/ruby/1.8/webrick/httpserver.rb:104:in service' /usr/lib/ruby/1.8/webrick/httpserver.rb:65:inrun’
/usr/lib/ruby/1.8/webrick/server.rb:173:in start_thread' /usr/lib/ruby/1.8/webrick/server.rb:162:instart_thread’
/usr/lib/ruby/1.8/webrick/server.rb:95:in start' /usr/lib/ruby/1.8/webrick/server.rb:92:instart’
/usr/lib/ruby/1.8/webrick/server.rb:23:in start' /usr/lib/ruby/1.8/webrick/server.rb:82:instart’
/usr/lib/ruby/gems/1.8/gems/rails-1.1.0/lib/webrick_server.rb:67:in
dispatch' /usr/lib/ruby/gems/1.8/gems/rails-1.1.0/lib/commands/servers/webrick.rb:59 /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:21:inrequire’
/usr/lib/ruby/gems/1.8/gems/activesupport-1.3.0/lib/active_support/dependencies.rb:136:in
require' /usr/lib/ruby/gems/1.8/gems/rails-1.1.0/lib/commands/server.rb:30 /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:21:inrequire’
/usr/lib/ruby/gems/1.8/gems/activesupport-1.3.0/lib/active_support/dependencies.rb:136:in
`require’
script/server:3

This error occured while loading the following files:
backend_controller.rb

Request

Parameters: None

Show session dump


flash: !map:ActionController::Flash::FlashHash {}

Response
Headers: {“cookie”=>[], “Cache-Control”=>“no-cache”}
------------------ERROR-----------------

I’ve just solved the problem without really understanding why what I
did solved the problem! I had not REMOVED the default
app/apis/backend_api.rb, but made a copy of it, edited the copy and
renamed it to product_api.rb. When I removed
backend_api.rb it worked.

Bealach

A couple more questions guys.

I’ve got things set up so that the product example works fine and
talks nicely to a
Perl XMLrpc client - thanks for all your suggestions and putting me on
the right track - life did get very good Derrick!

2 questions:

  1. The default documentation (method names and return types) that
    appears when the user visits http://localhost:3000/backend/invoke is
    concise and correct, but a bit terse. How can I give my users a little
    more? Maybe even include an example for them on the same page. Do I
    manually insert this in the rendered view? Or is there, like most
    things Ruby that I am discovering, a much more elegant way of doing
    this using RDoc?

  2. How do I go about providing full blown CRUD? If a user wants to
    insert 50 new books in my database using his/her Perl scripts, he/she
    will want to be able to send
    a hash or array of hashes and get some feedback (customized error codes
    etc.)

Bealach