rester 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/rester/client/adapters/adapter.rb +20 -24
- data/lib/rester/client/adapters/http_adapter/connection.rb +25 -4
- data/lib/rester/client/adapters/http_adapter.rb +16 -0
- data/lib/rester/client/resource.rb +59 -0
- data/lib/rester/client.rb +12 -5
- data/lib/rester/errors.rb +2 -15
- data/lib/rester/middleware/status_check.rb +15 -0
- data/lib/rester/middleware.rb +1 -0
- data/lib/rester/service/object.rb +103 -0
- data/lib/rester/service/request.rb +27 -0
- data/lib/rester/service.rb +118 -46
- data/lib/rester/utils.rb +5 -0
- data/lib/rester/version.rb +1 -1
- metadata +23 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f6fa57da0afc2d1f97912d9b52df6016e56fa1db
|
4
|
+
data.tar.gz: 25570c5f460cb04b857003e6956e4b28d7f00968
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3a7ac9757007d8e2bae0d4e31420dd9bc2c418c8bddd000d9e0b258d0161d029282e29963fdf7bcb27eba1340e97231c31af8a752336aaaa3b7d72a4db50c280
|
7
|
+
data.tar.gz: 207559692ae6d064e1bcd3ec44938e7853197d88a894365ae4220dbdfcfde03b9ad254dca8bdfa2cbb2f58038baa133eb9208edf4cce44efa91df0857ccb631e
|
@@ -25,32 +25,26 @@ module Rester
|
|
25
25
|
raise NotImplementedError
|
26
26
|
end
|
27
27
|
|
28
|
-
def request(verb,
|
28
|
+
def request(verb, path, params={}, &block)
|
29
|
+
params ||= {}
|
29
30
|
_validate_verb(verb)
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
public_send(
|
34
|
-
"#{verb}!",
|
35
|
-
"/#{method}/#{args.map(&:to_s).join('/')}",
|
36
|
-
params
|
37
|
-
)
|
31
|
+
_validate_params(params)
|
32
|
+
public_send("#{verb}!", path.to_s, params)
|
38
33
|
end
|
39
34
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
def get!(path, params={})
|
49
|
-
raise NotImplementedError
|
50
|
-
end
|
35
|
+
[:get, :post, :put, :delete].each do |verb|
|
36
|
+
##
|
37
|
+
# Define helper methods: get, post, put, delete
|
38
|
+
define_method(verb) { |*args, &block|
|
39
|
+
request(verb, *args, &block)
|
40
|
+
}
|
51
41
|
|
52
|
-
|
53
|
-
|
42
|
+
##
|
43
|
+
# Define implementation methods: get!, post!, put!, delete!
|
44
|
+
# These methods should be overridden by the specific adapter.
|
45
|
+
define_method("#{verb}!") { |*args, &block|
|
46
|
+
raise NotImplementedError
|
47
|
+
}
|
54
48
|
end
|
55
49
|
|
56
50
|
protected
|
@@ -62,8 +56,10 @@ module Rester
|
|
62
56
|
private
|
63
57
|
|
64
58
|
VALID_VERBS = {
|
65
|
-
get:
|
66
|
-
post:
|
59
|
+
get: true,
|
60
|
+
post: true,
|
61
|
+
put: true,
|
62
|
+
delete: true
|
67
63
|
}.freeze
|
68
64
|
|
69
65
|
VALID_ARG_TYPES = {
|
@@ -5,7 +5,7 @@ require 'uri'
|
|
5
5
|
module Rester
|
6
6
|
module Client::Adapters
|
7
7
|
class HttpAdapter::Connection
|
8
|
-
|
8
|
+
DEFAULT_DATA_HEADERS = {
|
9
9
|
"Content-Type".freeze => "application/x-www-form-urlencoded".freeze
|
10
10
|
}.freeze
|
11
11
|
|
@@ -23,9 +23,22 @@ module Rester
|
|
23
23
|
)
|
24
24
|
end
|
25
25
|
|
26
|
+
def delete(path, params={})
|
27
|
+
_http.delete(
|
28
|
+
_path(path, params[:query]),
|
29
|
+
_prepare_headers(params[:headers])
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
def put(path, params={})
|
34
|
+
encoded_data = _encode_data(params[:data])
|
35
|
+
headers = _prepare_data_headers(params[:headers])
|
36
|
+
_http.put(_path(path), encoded_data, headers)
|
37
|
+
end
|
38
|
+
|
26
39
|
def post(path, params={})
|
27
|
-
|
28
|
-
|
40
|
+
encoded_data = _encode_data(params[:data])
|
41
|
+
headers = _prepare_data_headers(params[:headers])
|
29
42
|
_http.post(_path(path), encoded_data, headers)
|
30
43
|
end
|
31
44
|
|
@@ -33,11 +46,19 @@ module Rester
|
|
33
46
|
|
34
47
|
def _path(path, query=nil)
|
35
48
|
u = url.dup
|
36
|
-
u.path
|
49
|
+
u.path = Utils.join_paths(u.path, path)
|
37
50
|
u.query = URI.encode_www_form(query) if query && !query.empty?
|
38
51
|
u.request_uri
|
39
52
|
end
|
40
53
|
|
54
|
+
def _encode_data(data)
|
55
|
+
URI.encode_www_form(data || {})
|
56
|
+
end
|
57
|
+
|
58
|
+
def _prepare_data_headers(headers)
|
59
|
+
DEFAULT_DATA_HEADERS.merge(_prepare_headers(headers))
|
60
|
+
end
|
61
|
+
|
41
62
|
def _http
|
42
63
|
Net::HTTP.new(url.hostname, url.port).tap { |http|
|
43
64
|
if (http.use_ssl=url.is_a?(URI::HTTPS))
|
@@ -14,10 +14,22 @@ module Rester
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def get!(path, params={})
|
17
|
+
_require_connection
|
17
18
|
_prepare_response(connection.get(path, headers: headers, query: params))
|
18
19
|
end
|
19
20
|
|
21
|
+
def delete!(path, params={})
|
22
|
+
_require_connection
|
23
|
+
_prepare_response(connection.delete(path, headers: headers, query: params))
|
24
|
+
end
|
25
|
+
|
26
|
+
def put!(path, params={})
|
27
|
+
_require_connection
|
28
|
+
_prepare_response(connection.put(path, headers: headers, data: params))
|
29
|
+
end
|
30
|
+
|
20
31
|
def post!(path, params={})
|
32
|
+
_require_connection
|
21
33
|
_prepare_response(connection.post(path, headers: headers, data: params))
|
22
34
|
end
|
23
35
|
|
@@ -26,6 +38,10 @@ module Rester
|
|
26
38
|
def _prepare_response(response)
|
27
39
|
[response.code.to_i, response.body]
|
28
40
|
end
|
41
|
+
|
42
|
+
def _require_connection
|
43
|
+
raise "not connected" unless connected?
|
44
|
+
end
|
29
45
|
end # HttpAdapter
|
30
46
|
end # Client::Adapters
|
31
47
|
end # Rester
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Rester
|
2
|
+
class Client
|
3
|
+
class Resource
|
4
|
+
attr_reader :client
|
5
|
+
attr_reader :path
|
6
|
+
|
7
|
+
def initialize(client, path='')
|
8
|
+
@client = client
|
9
|
+
@path = path
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(params={})
|
13
|
+
_request(:get, '', params)
|
14
|
+
end
|
15
|
+
|
16
|
+
def update(params={})
|
17
|
+
_request(:put, '', params)
|
18
|
+
end
|
19
|
+
|
20
|
+
def delete(params={})
|
21
|
+
_request(:delete, '', params)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def method_missing(meth, *args, &block)
|
27
|
+
meth = meth.to_s
|
28
|
+
|
29
|
+
unless args.length == 1
|
30
|
+
raise ArgumentError, "wrong number of arguments (#{args.length} for 1)"
|
31
|
+
end
|
32
|
+
|
33
|
+
arg = args.first
|
34
|
+
|
35
|
+
case arg
|
36
|
+
when Hash
|
37
|
+
_handle_search_or_create(meth, arg)
|
38
|
+
when String, Symbol
|
39
|
+
Resource.new(client, _path(meth, arg))
|
40
|
+
else
|
41
|
+
raise ArgumentError, "invalid argument type #{arg.inspect}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def _request(verb, path, params={})
|
46
|
+
client.request(verb, _path(path), params)
|
47
|
+
end
|
48
|
+
|
49
|
+
def _path(*args)
|
50
|
+
Utils.join_paths(path, *args)
|
51
|
+
end
|
52
|
+
|
53
|
+
def _handle_search_or_create(name, params)
|
54
|
+
verb, name = Utils.extract_method_verb(name)
|
55
|
+
_request(verb, name, params)
|
56
|
+
end
|
57
|
+
end # Object
|
58
|
+
end # Client
|
59
|
+
end # Rester
|
data/lib/rester/client.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
require 'json'
|
2
|
+
require 'active_support/inflector'
|
2
3
|
|
3
4
|
module Rester
|
4
5
|
class Client
|
5
6
|
autoload(:Adapters, 'rester/client/adapters')
|
7
|
+
autoload(:Resource, 'rester/client/resource')
|
6
8
|
|
7
9
|
attr_reader :adapter
|
8
10
|
|
@@ -13,6 +15,8 @@ module Rester
|
|
13
15
|
else
|
14
16
|
self.adapter = Adapters::HttpAdapter.new(*args)
|
15
17
|
end
|
18
|
+
|
19
|
+
@_resource = Resource.new(self)
|
16
20
|
end
|
17
21
|
|
18
22
|
def connect(*args)
|
@@ -20,7 +24,11 @@ module Rester
|
|
20
24
|
end
|
21
25
|
|
22
26
|
def connected?
|
23
|
-
adapter.connected? && adapter.get(
|
27
|
+
adapter.connected? && adapter.get('status').first == 200
|
28
|
+
end
|
29
|
+
|
30
|
+
def request(verb, path, params={}, &block)
|
31
|
+
_process_response(path, *adapter.request(verb, path, params, &block))
|
24
32
|
end
|
25
33
|
|
26
34
|
protected
|
@@ -34,17 +42,16 @@ module Rester
|
|
34
42
|
##
|
35
43
|
# Submits the method to the adapter.
|
36
44
|
def method_missing(meth, *args, &block)
|
37
|
-
|
38
|
-
_process_response(meth, *adapter.request(verb, meth, *args, &block))
|
45
|
+
@_resource.send(:method_missing, meth, *args, &block)
|
39
46
|
end
|
40
47
|
|
41
|
-
def _process_response(
|
48
|
+
def _process_response(path, status, body)
|
42
49
|
if status.between?(200, 299)
|
43
50
|
_parse_json(body)
|
44
51
|
elsif status == 400
|
45
52
|
raise Errors::RequestError, _parse_json(body)[:message]
|
46
53
|
elsif status == 404
|
47
|
-
raise Errors::
|
54
|
+
raise Errors::NotFoundError, _parse_json(body)[:message]
|
48
55
|
else
|
49
56
|
raise Errors::ServerError, _parse_json(body)[:message]
|
50
57
|
end
|
data/lib/rester/errors.rb
CHANGED
@@ -11,11 +11,8 @@ module Rester
|
|
11
11
|
end # Class Methods
|
12
12
|
|
13
13
|
class Error < StandardError; end
|
14
|
-
|
15
|
-
|
16
|
-
# Packet errors
|
17
|
-
class PacketError < Error; end
|
18
|
-
class InvalidEncodingError < PacketError; end
|
14
|
+
class MethodError < Error; end
|
15
|
+
class MethodDefinitionError < Error; end
|
19
16
|
|
20
17
|
#############
|
21
18
|
# Http Errors
|
@@ -35,18 +32,8 @@ module Rester
|
|
35
32
|
|
36
33
|
# 404 Not Found
|
37
34
|
class NotFoundError < RequestError; end
|
38
|
-
class InvalidMethodError < NotFoundError; end
|
39
35
|
|
40
36
|
# 500 ServerError
|
41
37
|
class ServerError < RequestError; end
|
42
|
-
|
43
|
-
##
|
44
|
-
# Server Errors
|
45
|
-
|
46
|
-
# General Errors
|
47
|
-
class InvalidValueError < Error; end
|
48
|
-
|
49
|
-
# Rester Errors
|
50
|
-
class ServiceNotDefinedError < Error; end
|
51
38
|
end # Errors
|
52
39
|
end # Rester
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Rester
|
2
|
+
module Middleware
|
3
|
+
##
|
4
|
+
# Provides a basic status check. Used by the Client#connected? method.
|
5
|
+
class StatusCheck < Base
|
6
|
+
def call(env)
|
7
|
+
if %r{\A/v[\d+]/status\z}.match(env['REQUEST_PATH'])
|
8
|
+
[200, {}, []]
|
9
|
+
else
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end # StatusCheck
|
14
|
+
end # Middleware
|
15
|
+
end # Rester
|
data/lib/rester/middleware.rb
CHANGED
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'active_support/inflector'
|
3
|
+
|
4
|
+
module Rester
|
5
|
+
class Service
|
6
|
+
class Object
|
7
|
+
REQUEST_METHOD_TO_INSTANCE_METHOD = {
|
8
|
+
'GET' => :get,
|
9
|
+
'PUT' => :update,
|
10
|
+
'DELETE' => :delete
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
REQUEST_METHOD_TO_CLASS_METHOD = {
|
14
|
+
'GET' => :search,
|
15
|
+
'POST' => :create
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
########################################################################
|
19
|
+
# DSL
|
20
|
+
########################################################################
|
21
|
+
class << self
|
22
|
+
##
|
23
|
+
# Specify the name of your identifier (Default: 'id')
|
24
|
+
def id(name)
|
25
|
+
(@id_name = name.to_sym).tap { |name|
|
26
|
+
# Create the accessor method for the ID.
|
27
|
+
define_method(name) { @id } unless name == :id
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Mount another Service Object
|
33
|
+
def mount(klass)
|
34
|
+
raise "Only other Service Objects can be mounted." unless klass < Object
|
35
|
+
start = self.name.split('::')[0..-2].join('::').length + 2
|
36
|
+
mounts[klass.name[start..-1].underscore] = klass
|
37
|
+
end
|
38
|
+
end # DSL
|
39
|
+
|
40
|
+
########################################################################
|
41
|
+
# Class Methods
|
42
|
+
########################################################################
|
43
|
+
class << self
|
44
|
+
def id_name
|
45
|
+
@id_name ||= :id
|
46
|
+
end
|
47
|
+
|
48
|
+
def id_param
|
49
|
+
"#{self.name.split('::').last.underscore}_#{id_name}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def mounts
|
53
|
+
(@__mounts ||= {})
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Helper method called at the class and instance level that calls the
|
58
|
+
# specified method on the passed object with the params. Allows for
|
59
|
+
# the arity of the method to be 0, 1 or -1.
|
60
|
+
def process!(obj, meth, params)
|
61
|
+
if obj.respond_to?(meth)
|
62
|
+
meth = obj.method(meth)
|
63
|
+
|
64
|
+
case meth.arity.abs
|
65
|
+
when 1
|
66
|
+
meth.call(params)
|
67
|
+
when 0
|
68
|
+
meth.call
|
69
|
+
else
|
70
|
+
raise MethodDefinitionError, "#{meth} must take 0 or 1 argument"
|
71
|
+
end
|
72
|
+
else
|
73
|
+
raise Errors::NotFoundError, meth
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def process(request_method, params={})
|
78
|
+
meth = REQUEST_METHOD_TO_CLASS_METHOD[request_method]
|
79
|
+
process!(self, meth, params)
|
80
|
+
end
|
81
|
+
end # Class Methods
|
82
|
+
|
83
|
+
attr_reader :id
|
84
|
+
|
85
|
+
def initialize(id)
|
86
|
+
@id = id
|
87
|
+
end
|
88
|
+
|
89
|
+
def id_param
|
90
|
+
self.class.id_param
|
91
|
+
end
|
92
|
+
|
93
|
+
def process(request_method, params={})
|
94
|
+
meth = REQUEST_METHOD_TO_INSTANCE_METHOD[request_method]
|
95
|
+
self.class.process!(self, meth, params)
|
96
|
+
end
|
97
|
+
|
98
|
+
def mounts
|
99
|
+
self.class.mounts
|
100
|
+
end
|
101
|
+
end # Object
|
102
|
+
end # Service
|
103
|
+
end # Rester
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
module Rester
|
4
|
+
class Service
|
5
|
+
class Request < Rack::Request
|
6
|
+
attr_reader :version
|
7
|
+
attr_reader :object_chain
|
8
|
+
|
9
|
+
def initialize(env)
|
10
|
+
super
|
11
|
+
_parse_path if valid?
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid?
|
15
|
+
path.length < 256 && %r{\A/v\d+/(\w+/?)+\z}.match(path)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def _parse_path
|
21
|
+
_, version, *pieces = path.split(/\/+/)
|
22
|
+
@version = version.downcase.to_sym
|
23
|
+
@object_chain = pieces.map(&:freeze)
|
24
|
+
end
|
25
|
+
end # Request
|
26
|
+
end # Service
|
27
|
+
end # Rester
|
data/lib/rester/service.rb
CHANGED
@@ -1,19 +1,41 @@
|
|
1
1
|
require 'uri'
|
2
2
|
require 'rack'
|
3
|
+
require 'active_support/inflector'
|
3
4
|
|
4
5
|
module Rester
|
5
6
|
class Service
|
7
|
+
autoload(:Request, 'rester/service/request')
|
8
|
+
autoload(:Object, 'rester/service/object')
|
9
|
+
|
6
10
|
##
|
7
11
|
# The base set of middleware to use for every service.
|
8
12
|
# Middleware will be executed in the order specified.
|
9
13
|
BASE_MIDDLEWARE = [
|
10
14
|
Rack::Head,
|
11
|
-
Middleware::ErrorHandling
|
15
|
+
Middleware::ErrorHandling,
|
16
|
+
Middleware::StatusCheck
|
12
17
|
].freeze
|
13
18
|
|
14
|
-
|
15
|
-
|
19
|
+
########################################################################
|
20
|
+
# DSL
|
21
|
+
########################################################################
|
22
|
+
class << self
|
23
|
+
###
|
24
|
+
# Middleware DSL
|
25
|
+
###
|
16
26
|
|
27
|
+
def use(klass, *args)
|
28
|
+
_middleware << [klass, *args]
|
29
|
+
end
|
30
|
+
|
31
|
+
def _middleware
|
32
|
+
@__middleware ||= BASE_MIDDLEWARE.dup
|
33
|
+
end
|
34
|
+
end # DSL
|
35
|
+
|
36
|
+
########################################################################
|
37
|
+
# Class Methods
|
38
|
+
########################################################################
|
17
39
|
class << self
|
18
40
|
def instance
|
19
41
|
@instance ||= new
|
@@ -29,24 +51,35 @@ module Rester
|
|
29
51
|
instance.public_send(meth, *args, &block)
|
30
52
|
end
|
31
53
|
|
32
|
-
|
33
|
-
|
34
|
-
|
54
|
+
def versions
|
55
|
+
@__versions ||= constants.map(&:to_s).select { |c|
|
56
|
+
c.match(/^V\d{1,3}$/)
|
57
|
+
}.map(&:downcase).map(&:to_sym)
|
58
|
+
end
|
35
59
|
|
36
|
-
def
|
37
|
-
|
60
|
+
def version_module(version)
|
61
|
+
(@__version_modules ||= {})[version.to_sym] ||= _load_version_module(version)
|
38
62
|
end
|
39
63
|
|
40
|
-
def
|
41
|
-
|
64
|
+
def _load_version_module(version)
|
65
|
+
versions.include?(version.to_sym) or
|
66
|
+
raise ArgumentError, "invalid version #{version.inspect}"
|
67
|
+
|
68
|
+
const_get(version.to_s.upcase)
|
42
69
|
end
|
43
|
-
end # Class methods
|
44
70
|
|
45
|
-
|
71
|
+
def objects(version_module)
|
72
|
+
(@__objects ||= {})[version_module] ||= _load_objects(version_module)
|
73
|
+
end
|
46
74
|
|
47
|
-
|
48
|
-
|
49
|
-
|
75
|
+
def _load_objects(version_module)
|
76
|
+
version_module.constants.map { |c|
|
77
|
+
version_module.const_get(c)
|
78
|
+
}.select { |c|
|
79
|
+
c.is_a?(Class) && c < Service::Object
|
80
|
+
}
|
81
|
+
end
|
82
|
+
end # Class methods
|
50
83
|
|
51
84
|
##
|
52
85
|
# To be called by Rack. Wraps the app in middleware.
|
@@ -64,18 +97,12 @@ module Rester
|
|
64
97
|
end
|
65
98
|
|
66
99
|
##
|
67
|
-
#
|
100
|
+
# Process the request.
|
68
101
|
#
|
69
102
|
# Calls methods that may modify instance variables, so the instance should
|
70
103
|
# be dup'd beforehand.
|
71
104
|
def call!(env)
|
72
|
-
|
73
|
-
_process_request
|
74
|
-
end
|
75
|
-
|
76
|
-
##
|
77
|
-
# Built in service method called by Client#connected?
|
78
|
-
def test_connection(params={})
|
105
|
+
_process_request(Request.new(env))
|
79
106
|
end
|
80
107
|
|
81
108
|
private
|
@@ -91,45 +118,90 @@ module Rester
|
|
91
118
|
}.to_app
|
92
119
|
end
|
93
120
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
121
|
+
##
|
122
|
+
# Validates the request, calls the appropriate Service::Object method and
|
123
|
+
# returns a valid Rack response.
|
124
|
+
def _process_request(request)
|
125
|
+
_error!(Errors::NotFoundError) unless request.valid?
|
126
|
+
_validate_version(request)
|
127
|
+
retval = _call_method(request)
|
100
128
|
_response(request.post? ? 201 : 200, _prepare_response(retval))
|
101
129
|
end
|
102
130
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
131
|
+
##
|
132
|
+
# Validates that the version of the request matches a defined version module.
|
133
|
+
# If the version is not found, it throws a NotFoundError (HTTP 404).
|
134
|
+
def _validate_version(request)
|
135
|
+
unless self.class.versions.include?(request.version)
|
136
|
+
_error!(Errors::NotFoundError)
|
108
137
|
end
|
138
|
+
end
|
109
139
|
|
110
|
-
|
140
|
+
##
|
141
|
+
# Calls the appropriate method on the appropriate Service::Object for the
|
142
|
+
# request.
|
143
|
+
def _call_method(request)
|
144
|
+
params = request.params
|
145
|
+
retval = nil
|
146
|
+
|
147
|
+
name, id, *object_chain = request.object_chain
|
148
|
+
obj = _load_object(request, name)
|
149
|
+
|
150
|
+
loop {
|
151
|
+
obj = obj.new(id) if id
|
152
|
+
|
153
|
+
if object_chain.empty?
|
154
|
+
retval = obj.process(request.request_method, params)
|
155
|
+
break
|
156
|
+
end
|
157
|
+
|
158
|
+
params.merge!(obj.id_param => obj.id)
|
159
|
+
name, id, *object_chain = object_chain
|
160
|
+
obj = obj.mounts[name] or raise Errors::NotFoundError
|
161
|
+
}
|
162
|
+
|
163
|
+
retval
|
111
164
|
end
|
112
165
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
166
|
+
##
|
167
|
+
# Loads the appropriate Service::Object for the request. This will return
|
168
|
+
# the class, not an instance.
|
169
|
+
def _load_object(request, name)
|
170
|
+
_version_module(request).const_get(name.camelcase.singularize)
|
171
|
+
rescue NameError
|
172
|
+
_error!(Errors::NotFoundError)
|
117
173
|
end
|
118
174
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
175
|
+
##
|
176
|
+
# Returns the module specified by the version in the request.
|
177
|
+
def _version_module(request)
|
178
|
+
self.class.version_module(request.version)
|
179
|
+
end
|
180
|
+
|
181
|
+
##
|
182
|
+
# Prepares the retval from a Service::Object method to be returned to the
|
183
|
+
# client (i.e., validates it and dumps it as JSON).
|
184
|
+
def _prepare_response(retval)
|
185
|
+
retval ||= {}
|
186
|
+
|
187
|
+
unless retval.is_a?(Hash)
|
188
|
+
_error!(Errors::ServerError, "Invalid response: #{retval.inspect}")
|
124
189
|
end
|
190
|
+
|
191
|
+
JSON.dump(retval)
|
125
192
|
end
|
126
193
|
|
127
|
-
|
128
|
-
|
194
|
+
##
|
195
|
+
# Returns a valid rack response.
|
196
|
+
def _response(status, body=nil, headers={})
|
197
|
+
body = [body].compact
|
129
198
|
headers = headers.merge("Content-Type" => "application/json")
|
130
199
|
Rack::Response.new(body, status, headers).finish
|
131
200
|
end
|
132
201
|
|
202
|
+
##
|
203
|
+
# Throws an exception (instead of raising it). This is done for performance
|
204
|
+
# reasons. The exception will be caught in the ErrorHandling middleware.
|
133
205
|
def _error!(klass, message=nil)
|
134
206
|
Errors.throw_error!(klass, message)
|
135
207
|
end
|
data/lib/rester/utils.rb
CHANGED
data/lib/rester/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rester
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Honer
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-10-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
@@ -31,6 +31,20 @@ dependencies:
|
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 1.5.2
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: activesupport
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 4.0.13
|
41
|
+
type: :runtime
|
42
|
+
prerelease: false
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 4.0.13
|
34
48
|
- !ruby/object:Gem::Dependency
|
35
49
|
name: rspec
|
36
50
|
requirement: !ruby/object:Gem::Requirement
|
@@ -89,8 +103,8 @@ dependencies:
|
|
89
103
|
version: 4.0.0
|
90
104
|
description: A framework for creating simple RESTful interfaces between services.
|
91
105
|
email:
|
92
|
-
- robert@
|
93
|
-
- kayvon@
|
106
|
+
- robert@payout.com
|
107
|
+
- kayvon@payout.com
|
94
108
|
executables: []
|
95
109
|
extensions: []
|
96
110
|
extra_rdoc_files: []
|
@@ -101,15 +115,19 @@ files:
|
|
101
115
|
- lib/rester/client/adapters/adapter.rb
|
102
116
|
- lib/rester/client/adapters/http_adapter.rb
|
103
117
|
- lib/rester/client/adapters/http_adapter/connection.rb
|
118
|
+
- lib/rester/client/resource.rb
|
104
119
|
- lib/rester/errors.rb
|
105
120
|
- lib/rester/middleware.rb
|
106
121
|
- lib/rester/middleware/base.rb
|
107
122
|
- lib/rester/middleware/error_handling.rb
|
123
|
+
- lib/rester/middleware/status_check.rb
|
108
124
|
- lib/rester/railtie.rb
|
109
125
|
- lib/rester/service.rb
|
126
|
+
- lib/rester/service/object.rb
|
127
|
+
- lib/rester/service/request.rb
|
110
128
|
- lib/rester/utils.rb
|
111
129
|
- lib/rester/version.rb
|
112
|
-
homepage: http://github.com/
|
130
|
+
homepage: http://github.com/payout/rester
|
113
131
|
licenses:
|
114
132
|
- BSD
|
115
133
|
metadata: {}
|