rubyrest 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +14 -1
- data/README +19 -6
- data/Rakefile +1 -1
- data/bin/rubyrest +12 -8
- data/examples/hello.rb +10 -10
- data/lib/rubyrest/atom.rb +7 -0
- data/lib/rubyrest/client.rb +122 -60
- data/lib/rubyrest/config.rb +9 -7
- data/lib/rubyrest/engine.rb +12 -8
- data/lib/rubyrest/servlets.rb +5 -1
- metadata +2 -2
data/CHANGELOG
CHANGED
@@ -1,8 +1,21 @@
|
|
1
|
+
== What's next?
|
2
|
+
|
3
|
+
* Introduce the concept of 'security authority' so that multiple deployed instances of rubyrest can be federated by a single authentication and authorization service.
|
4
|
+
* Use mongrel as the HTTP server implementation, instead of WEBrick
|
5
|
+
* Refactor code, style it more 'a la' Ruby.
|
6
|
+
* Provide more complex examples, such as Database Configurations
|
7
|
+
|
8
|
+
== Release 0.0.4
|
9
|
+
|
10
|
+
* Module RubyRest::Client has been redesigned into class RubyRest::Client::Default which offers a higher level api by translating create, retrieve, update and delete method calls into proper HTTP GET, POST, PUT and DELETE requests.
|
11
|
+
* Engine configurations are now externalized so they can be provided programmatically as Hashes or loaded from YAML files.
|
12
|
+
* The rubyrest command line now supports different deployment environments (dev, live)
|
13
|
+
|
1
14
|
== Release 0.0.3
|
2
15
|
|
3
16
|
* Added module RubyRest::Client, providing a convenience client to REST APIs deployed with Ruby-on-Rest
|
4
17
|
* Improved Atom representation of resources (feeds, entries and service documents)
|
5
|
-
* Dashboard (service document) can now be customized by
|
18
|
+
* Dashboard (service document) can now be customized by developers by implementing a class with name Dashboard.
|
6
19
|
|
7
20
|
== Release 0.0.2
|
8
21
|
|
data/README
CHANGED
@@ -30,15 +30,27 @@ If you have any comments or suggestions please send an email to pedro dot gutier
|
|
30
30
|
|
31
31
|
Please have a look at the examples provided, they are simple enough to let you grasp how rubyrest works.
|
32
32
|
|
33
|
-
=== Starting
|
33
|
+
=== Starting the service
|
34
34
|
|
35
35
|
Ruby-on-Rest provides a shell command. Open your console, and type the following:
|
36
36
|
|
37
|
-
rubyrest
|
37
|
+
rubyrest dev <my_service> (for development deployment)
|
38
|
+
rubyrest live <my_service> (for live deployment)
|
38
39
|
|
39
|
-
|
40
|
+
This will first look at a YAML file called <my_service>_dev.yaml or <my_service>_live.yaml under the
|
41
|
+
current path.
|
40
42
|
|
41
|
-
|
43
|
+
Ruby-on-Rest can also be embedded in ruby code. This is useful for testing purposes:
|
44
|
+
|
45
|
+
config = {
|
46
|
+
"service" => "hello",
|
47
|
+
"prefix" => "acme",
|
48
|
+
"serviceport" => 9003
|
49
|
+
"daemon" => true
|
50
|
+
"entities" => [ "welcomeservice" ]
|
51
|
+
}
|
52
|
+
|
53
|
+
engine = RubyRest::Engine.new( config )
|
42
54
|
engine.start
|
43
55
|
# ...
|
44
56
|
# do some http calls here
|
@@ -48,7 +60,8 @@ Ruby-on-Rest can also be embedded in ruby code. This is useful for testing purpo
|
|
48
60
|
|
49
61
|
=== Configuring your service
|
50
62
|
|
51
|
-
Ruby-on-Rest will try to load a file name <my_service>.rb which
|
52
|
-
|
63
|
+
Ruby-on-Rest will try to load a file name <my_service>.rb which provides the implementation of the service.
|
64
|
+
|
65
|
+
|
53
66
|
|
54
67
|
|
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ require 'fileutils'
|
|
6
6
|
include FileUtils
|
7
7
|
|
8
8
|
NAME = "rubyrest"
|
9
|
-
VERS = "0.0.
|
9
|
+
VERS = "0.0.4"
|
10
10
|
CLEAN.include ['**/.*.sw?', 'pkg/*', '.config', 'doc/*', 'coverage/*']
|
11
11
|
RDOC_OPTS = ['--quiet', '--title', "Ruby-on-Rest: A simple REST framework for Ruby",
|
12
12
|
"--opname", "index.html",
|
data/bin/rubyrest
CHANGED
@@ -7,20 +7,24 @@ require 'rubygems'
|
|
7
7
|
require 'rubyrest'
|
8
8
|
|
9
9
|
service = ARGV[1]
|
10
|
-
|
11
|
-
action = ARGV[0]
|
10
|
+
deploy_mode = ARGV[0]
|
12
11
|
|
13
|
-
if
|
14
|
-
puts "Usage: rubyrest
|
12
|
+
if service == nil or deploy_mode == nil
|
13
|
+
puts "Usage: rubyrest dev|live <your_service>"
|
15
14
|
puts "Ruby-on-Rest: Simple REST for Ruby."
|
16
15
|
puts
|
17
16
|
puts "Examples:"
|
18
|
-
puts " rubyrest
|
19
|
-
puts " rubyrest
|
17
|
+
puts " rubyrest dev grape"
|
18
|
+
puts " rubyrest live grape"
|
20
19
|
puts
|
21
20
|
puts "For more information see http://rubyrest.rubyforge.org"
|
22
21
|
else
|
23
|
-
|
24
|
-
|
22
|
+
# load the yaml file for the
|
23
|
+
# deploy specific configuration, and build a hash out of it
|
24
|
+
params = YAML::load_file( "#{service}_#{deploy_mode}.yaml" )
|
25
|
+
params[ "service" ] = service
|
26
|
+
|
27
|
+
engine = RubyRest::Engine.new( params )
|
28
|
+
engine.start
|
25
29
|
end
|
26
30
|
|
data/examples/hello.rb
CHANGED
@@ -11,18 +11,18 @@ module Acme
|
|
11
11
|
# connectivity.
|
12
12
|
class Config < RubyRest::SimpleConfig
|
13
13
|
|
14
|
-
# Inits the internal hash of
|
15
|
-
# configuration options. This is the minimal expression
|
16
|
-
# of a Ruby-on-Rest configuration hash.
|
17
|
-
def initialize
|
18
|
-
@hash = {
|
19
|
-
:servicemodel => [ "welcomeservice" ],
|
20
|
-
:serviceport => 9001
|
21
|
-
}
|
22
|
-
end
|
23
|
-
|
24
14
|
end
|
25
15
|
|
16
|
+
# The dashboard that provides an entry point to the
|
17
|
+
# application
|
18
|
+
class Dashboard
|
19
|
+
|
20
|
+
def self.rest_retrieve( principal )
|
21
|
+
[ "welcomeservice" ]
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
26
|
# The domain service that actually implements
|
27
27
|
# 'business' logic. In this case, it's just going to say "Hello!"
|
28
28
|
# by returning a HelloBean object
|
data/lib/rubyrest/atom.rb
CHANGED
@@ -167,6 +167,13 @@ module RubyRest
|
|
167
167
|
def id
|
168
168
|
text( "/entry/moodisland:content/id" )
|
169
169
|
end
|
170
|
+
|
171
|
+
# Overrides the default implementation
|
172
|
+
# by returning a new Ruby-on-Rest Atom Document
|
173
|
+
def clone
|
174
|
+
self.class.new self.to_s
|
175
|
+
end
|
176
|
+
|
170
177
|
end
|
171
178
|
|
172
179
|
end
|
data/lib/rubyrest/client.rb
CHANGED
@@ -4,69 +4,131 @@ module RubyRest
|
|
4
4
|
# to REST services offered by Ruby-on-REST.
|
5
5
|
module Client
|
6
6
|
|
7
|
-
#
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
def hash2entry( data )
|
17
|
-
doc = RubyRest::Atom::Entry::Document.new
|
18
|
-
entry = REXML::Element.new( "entry", doc )
|
19
|
-
content = REXML::Element.new( "content", entry )
|
20
|
-
data.each { |name,value|
|
21
|
-
body = REXML::Element.new( name.to_s, content )
|
22
|
-
body.text = value
|
23
|
-
}
|
24
|
-
return doc
|
25
|
-
end
|
26
|
-
|
27
|
-
# Parses the response body string as a Ruby-on-Rest Entry document,
|
28
|
-
def str2entry( rsp )
|
29
|
-
begin
|
30
|
-
RubyRest::Atom::Entry::Document.new( rsp.body ) if response.body
|
31
|
-
rescue => e
|
32
|
-
return nil
|
7
|
+
# Default client for web services deployed with
|
8
|
+
# Ruby-on-Rest. Translates create, retrieve, update and
|
9
|
+
# delete methods into POST, GET, PUT and DELETE http requests
|
10
|
+
class Default
|
11
|
+
|
12
|
+
# Configures the server name and port
|
13
|
+
def self.with_server name, port
|
14
|
+
@host = name
|
15
|
+
@port = port
|
33
16
|
end
|
17
|
+
|
18
|
+
# Returns the hostname of the service to
|
19
|
+
# connect to
|
20
|
+
def self.host
|
21
|
+
@host
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the port number on which to
|
25
|
+
# connect to
|
26
|
+
def self.port
|
27
|
+
@port
|
28
|
+
end
|
29
|
+
|
30
|
+
# Converts the specified hash of data into a
|
31
|
+
# query string, then performs a GET http request.
|
32
|
+
# The response body is returned as an an Atom document if
|
33
|
+
# the response status code is 200.
|
34
|
+
def retrieve( path, data, api_key )
|
35
|
+
path << to_query_string( data ) if data
|
36
|
+
headers = prepare_headers( api_key )
|
37
|
+
rsp = http.get( path, headers )
|
38
|
+
return to_xml( rsp ) if rsp.code.to_i == 200
|
39
|
+
end
|
40
|
+
|
41
|
+
# Converts the specified hash of data into a
|
42
|
+
# simplified Atom Entry, then performs a POST http request.
|
43
|
+
# The response body is returned as an an Atom Entry if
|
44
|
+
# the response status code is 201.
|
45
|
+
def create( path, data, api_key )
|
46
|
+
body = nil
|
47
|
+
body = hash2entry( data ).to_s if data != nil
|
48
|
+
headers = prepare_headers( api_key )
|
49
|
+
rsp = http.post( path, body, headers )
|
50
|
+
return to_xml( rsp ) if rsp.code.to_i == 201
|
51
|
+
end
|
52
|
+
|
53
|
+
# Converts the specified hash of data into a
|
54
|
+
# simplified Atom Entry, then performs a PUT http request.
|
55
|
+
# The response body is returned as an an Atom Entry if
|
56
|
+
# the response status code is 200.
|
57
|
+
def update( path, data, api_key )
|
58
|
+
body = nil
|
59
|
+
body = hash2entry( data ).to_s if data != nil
|
60
|
+
headers = prepare_headers( api_key )
|
61
|
+
rsp = http.put( path, body, headers )
|
62
|
+
return to_xml( rsp ) if rsp.code.to_i == 200
|
63
|
+
end
|
64
|
+
|
65
|
+
# Converts the specified hash of data into a
|
66
|
+
# query string, then performs a DELETE http request.
|
67
|
+
# This method simply returns the response status code
|
68
|
+
def delete( path, data, api_key )
|
69
|
+
path << to_query_string( data ) if data
|
70
|
+
headers = prepare_headers( api_key )
|
71
|
+
rsp = http.delete( path, headers )
|
72
|
+
rsp.code.to_i
|
73
|
+
end
|
74
|
+
|
75
|
+
# Convenience method that returns the
|
76
|
+
# service document from the service endpoint
|
77
|
+
def dashboard( api_key )
|
78
|
+
retrieve( "/", nil, api_key )
|
79
|
+
end
|
80
|
+
|
81
|
+
# Convenience method that returns a new HTTP object
|
82
|
+
# for each call
|
83
|
+
def http
|
84
|
+
Net::HTTP.new( self.class.host, self.class.port )
|
85
|
+
end
|
86
|
+
|
87
|
+
# Builds a headers hash, with the specified
|
88
|
+
# authorization token if not nil
|
89
|
+
def prepare_headers( api_key = nil )
|
90
|
+
headers = { "Content-Type" => "text/xml; charset=utf-8" }
|
91
|
+
headers[ "token" ] = api_key if api_key != nil
|
92
|
+
return headers
|
93
|
+
end
|
94
|
+
|
95
|
+
# Converts the specified hash of data into a simplified
|
96
|
+
# Atom Entry document.
|
97
|
+
def hash2entry( data )
|
98
|
+
doc = RubyRest::Atom::Entry::Document.new
|
99
|
+
entry = REXML::Element.new( "entry", doc )
|
100
|
+
content = REXML::Element.new( "content", entry )
|
101
|
+
data.each { |name,value|
|
102
|
+
body = REXML::Element.new( name.to_s, content )
|
103
|
+
body.text = value
|
104
|
+
}
|
105
|
+
return doc
|
106
|
+
end
|
107
|
+
|
108
|
+
# Parses the response body string as a Ruby-on-Rest XML Document,
|
109
|
+
# which can be a Feed or Entry, or Service Document
|
110
|
+
def to_xml( rsp )
|
111
|
+
begin
|
112
|
+
RubyRest::Atom::Entry::Document.new( rsp.body ) if rsp.body
|
113
|
+
rescue => e
|
114
|
+
puts "unable to parse response body: " + e.message
|
115
|
+
puts "---- response body ----"
|
116
|
+
puts rsp.body
|
117
|
+
puts "-----------------------"
|
118
|
+
return nil
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Reusable method that creates a query string
|
123
|
+
# with the specified hash of data
|
124
|
+
def to_query_string( data )
|
125
|
+
qs = "?"
|
126
|
+
params.each{ |k,v| qs << "#{k}=#{v}&" }
|
127
|
+
qs.chop!
|
128
|
+
end
|
129
|
+
|
34
130
|
end
|
35
131
|
|
36
|
-
# Reusable method that creates a query string
|
37
|
-
# with the specified hash of data
|
38
|
-
def to_query_string( data )
|
39
|
-
qs = "?"
|
40
|
-
params.each{ |k,v| qs << "#{k}=#{v}&" }
|
41
|
-
qs.chop!
|
42
|
-
end
|
43
|
-
|
44
|
-
# Performs a POST request and returns the raw response object
|
45
|
-
# The data (a hash of name,value pairs) is converted to an
|
46
|
-
# simplified Atom Entry
|
47
|
-
def post( server, port, path, data, token )
|
48
|
-
body = nil
|
49
|
-
body = hash2entry( data ).to_s if data != nil
|
50
|
-
headers = prepare_headers( token )
|
51
|
-
rsp = Net::HTTP.new( server, port ).post( path, body, headers )
|
52
|
-
[ rsp.code.to_i, str2entry( rsp ) ]
|
53
|
-
end
|
54
|
-
|
55
|
-
# Performs a GET request and returns the raw response object
|
56
|
-
# The data (a hash of name,value pairs) is converted to a query
|
57
|
-
# string, then concatenated to the path.
|
58
|
-
def get( server, port, path, data, token )
|
59
|
-
path << to_query_string( data ) if data
|
60
|
-
headers = prepare_headers( token )
|
61
|
-
rsp = Net::HTTP.new( server, port ).get( path, headers )
|
62
|
-
[ rsp.code.to_i, str2entry( rsp ) ]
|
63
|
-
end
|
64
|
-
|
65
|
-
|
66
|
-
|
67
132
|
end
|
68
133
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
134
|
end
|
data/lib/rubyrest/config.rb
CHANGED
@@ -13,11 +13,7 @@ module RubyRest
|
|
13
13
|
#
|
14
14
|
# module MyService
|
15
15
|
# class Config < RubyRest::SimpleConfig
|
16
|
-
#
|
17
|
-
# @hash = {
|
18
|
-
# ... my config here ..
|
19
|
-
# }
|
20
|
-
# end
|
16
|
+
#
|
21
17
|
# end
|
22
18
|
# end
|
23
19
|
#
|
@@ -25,6 +21,12 @@ module RubyRest
|
|
25
21
|
class SimpleConfig
|
26
22
|
include RubyRest::Tools
|
27
23
|
|
24
|
+
# Initializes a new configuration with the specified
|
25
|
+
# hash of data
|
26
|
+
def initialize( hash )
|
27
|
+
@hash = hash
|
28
|
+
end
|
29
|
+
|
28
30
|
# Overrides the specified configuration option
|
29
31
|
# with its new value
|
30
32
|
def []=( name, value )
|
@@ -45,7 +47,7 @@ module RubyRest
|
|
45
47
|
|
46
48
|
# Dumps all the configuration options
|
47
49
|
def to_s
|
48
|
-
@hash.each{ |k,v| puts "#{k}
|
50
|
+
@hash.each{ |k,v| puts "key: #{k}, value: #{v}" }
|
49
51
|
end
|
50
52
|
|
51
53
|
end
|
@@ -60,7 +62,7 @@ module RubyRest
|
|
60
62
|
# will delegate to a more specialized method, according to the
|
61
63
|
# :adapter config option
|
62
64
|
def connect_to_database
|
63
|
-
adapter_method = "#{
|
65
|
+
adapter_method = "#{self[:adapter]}_connect"
|
64
66
|
error( 004, self, adapter_method ) if !self.respond_to?( adapter_method )
|
65
67
|
@db = self.method( adapter_method ).call
|
66
68
|
error( 005, self, adapter_method ) if @db == nil
|
data/lib/rubyrest/engine.rb
CHANGED
@@ -14,14 +14,18 @@ module RubyRest
|
|
14
14
|
# engine configuration
|
15
15
|
attr_reader :config
|
16
16
|
|
17
|
-
# Creates a new RubyRest engine, for the
|
18
|
-
#
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
# Creates a new RubyRest engine, for the specified
|
18
|
+
# hash of configuration data. The specified hash of params
|
19
|
+
# will be 'interned' so that config keys are accessible
|
20
|
+
# as symbols instead of strings.
|
21
|
+
def initialize( original )
|
22
|
+
params = {}
|
23
|
+
original.each{ |k,v| params[ k.intern ] = v }
|
24
|
+
@service = params[ :service ]
|
25
|
+
@prefix = params[ :prefix ]
|
22
26
|
service_module = to_module_name( @prefix, @service )
|
23
27
|
require @service
|
24
|
-
@config = to_class( service_module, "config" ).new
|
28
|
+
@config = to_class( service_module, "config" ).new( params )
|
25
29
|
@config[ :servicemodule ] = service_module
|
26
30
|
end
|
27
31
|
|
@@ -31,7 +35,7 @@ module RubyRest
|
|
31
35
|
# 2. launch the webserver, in daemon mode unless false is
|
32
36
|
# specified in the configuration
|
33
37
|
def start
|
34
|
-
configure_database if @config.has( :
|
38
|
+
configure_database if @config.has( :adapter )
|
35
39
|
@server = RubyRest::Server.new( @config )
|
36
40
|
@server.mount "/", CRUDServlet
|
37
41
|
if @config.has( :daemon ) and @config[ :daemon ] == false
|
@@ -51,7 +55,7 @@ module RubyRest
|
|
51
55
|
def configure_database
|
52
56
|
@config.connect_to_database
|
53
57
|
@config.setup_persistence
|
54
|
-
if @config[ :
|
58
|
+
if @config[ :destroy ] == true
|
55
59
|
@config.init_schema
|
56
60
|
@config.load_initial_data
|
57
61
|
end
|
data/lib/rubyrest/servlets.rb
CHANGED
@@ -38,7 +38,11 @@ module RubyRest
|
|
38
38
|
@model = params[1]
|
39
39
|
@id = params[2]
|
40
40
|
@property = params[3]
|
41
|
-
|
41
|
+
begin
|
42
|
+
@body = REXML::Document.new( request.body ) if request.body != nil
|
43
|
+
rescue => e
|
44
|
+
puts "unable to parse request body: #{request.body}"
|
45
|
+
end
|
42
46
|
end
|
43
47
|
|
44
48
|
def resolve_custom_method
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.1
|
|
3
3
|
specification_version: 1
|
4
4
|
name: rubyrest
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0.
|
7
|
-
date: 2007-04-
|
6
|
+
version: 0.0.4
|
7
|
+
date: 2007-04-15 00:00:00 +02:00
|
8
8
|
summary: REST framework for Ruby.
|
9
9
|
require_paths:
|
10
10
|
- lib
|