served 0.3.3 → 0.4.0.rc1
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/.gitignore +2 -0
- data/.rubocop.yml +53 -0
- data/Rakefile +12 -1
- data/lib/served/attribute/base.rb +1 -2
- data/lib/served/attribute.rb +1 -1
- data/lib/served/backends/base.rb +1 -2
- data/lib/served/backends/http.rb +25 -20
- data/lib/served/backends/httparty.rb +22 -20
- data/lib/served/backends/patron.rb +23 -18
- data/lib/served/backends.rb +3 -5
- data/lib/served/config.rb +2 -2
- data/lib/served/error.rb +1 -2
- data/lib/served/http_client.rb +5 -8
- data/lib/served/resource/attributable.rb +4 -9
- data/lib/served/resource/base.rb +12 -10
- data/lib/served/resource/configurable.rb +5 -9
- data/lib/served/resource/http_errors.rb +1 -31
- data/lib/served/resource/invalid_attribute_serializer.rb +1 -3
- data/lib/served/resource/requestable.rb +13 -17
- data/lib/served/resource/response_invalid.rb +8 -6
- data/lib/served/resource/serializable.rb +14 -9
- data/lib/served/resource/validatable.rb +13 -17
- data/lib/served/serializers/json.rb +10 -10
- data/lib/served/serializers/json_api.rb +9 -3
- data/lib/served/serializers/serialization_error.rb +1 -3
- data/lib/served/version.rb +1 -1
- data/served.gemspec +5 -4
- metadata +20 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d22e0da5fe463903fa6699329ba5f2f4fad64905
|
4
|
+
data.tar.gz: 5572ef473d464638fb46541e5367969fe784d766
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6540cbd7e3f2b875d9c22c8b5d412ccc892b2022d6ec8a84b21b434201e5d079dd4f69301e64f6ef96a56b96893d72e792810a1be279ab1bd8d64690c9021b7
|
7
|
+
data.tar.gz: be4a8d52c93ea6f42d1d5268972c307348963f411ef145dba65921f771dd2722a0d59b6f6332df0c0eab30d63b5779439a3c2df241d2b968218ca2c86e386026
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
Style/ClassAndModuleChildren:
|
2
|
+
Enabled: false
|
3
|
+
|
4
|
+
Style/ConditionalAssignment:
|
5
|
+
Enabled: false
|
6
|
+
|
7
|
+
Style/RaiseArgs:
|
8
|
+
EnforcedStyle: compact
|
9
|
+
|
10
|
+
Style/FrozenStringLiteralComment:
|
11
|
+
Enabled: false
|
12
|
+
|
13
|
+
Style/Documentation:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
Style/MultipleComparison:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
Style/StringLiterals:
|
20
|
+
Enabled: false
|
21
|
+
|
22
|
+
Style/SymbolArray:
|
23
|
+
Enabled: false
|
24
|
+
|
25
|
+
Layout/MultilineMethodCallIndentation:
|
26
|
+
EnforcedStyle: indented
|
27
|
+
|
28
|
+
Layout/MultilineOperationIndentation:
|
29
|
+
Enabled: false
|
30
|
+
|
31
|
+
Metrics/LineLength:
|
32
|
+
Max: 130
|
33
|
+
|
34
|
+
Metrics/MethodLength:
|
35
|
+
Max: 20
|
36
|
+
|
37
|
+
Metrics/AbcSize:
|
38
|
+
Max: 35
|
39
|
+
|
40
|
+
Metrics/PerceivedComplexity:
|
41
|
+
Max: 15
|
42
|
+
|
43
|
+
Metrics/CyclomaticComplexity:
|
44
|
+
Max: 15
|
45
|
+
|
46
|
+
Metrics/BlockLength:
|
47
|
+
Enabled: false
|
48
|
+
|
49
|
+
Lint/UnifiedInteger:
|
50
|
+
Enabled: false
|
51
|
+
|
52
|
+
Performance/RegexpMatch:
|
53
|
+
Enabled: false
|
data/Rakefile
CHANGED
@@ -1,6 +1,17 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
require "rspec/core/rake_task"
|
3
|
+
require "rubocop/rake_task"
|
3
4
|
|
4
5
|
RSpec::Core::RakeTask.new(:spec)
|
5
6
|
|
6
|
-
|
7
|
+
RuboCop::RakeTask.new(:rubocop) do |t|
|
8
|
+
t.options = ['--display-cop-names']
|
9
|
+
end
|
10
|
+
|
11
|
+
desc 'Run rubocop and rspec'
|
12
|
+
task :ci do
|
13
|
+
Rake::Task["spec"].invoke
|
14
|
+
Rake::Task["rubocop"].invoke
|
15
|
+
end
|
16
|
+
|
17
|
+
task default: :ci
|
data/lib/served/attribute.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require_relative 'attribute/base'
|
1
|
+
require_relative 'attribute/base'
|
data/lib/served/backends/base.rb
CHANGED
data/lib/served/backends/http.rb
CHANGED
@@ -1,49 +1,54 @@
|
|
1
1
|
require 'http'
|
2
2
|
module Served
|
3
3
|
module Backends
|
4
|
-
#HTTP Backend uses {https://github.com/httprb/http HTTP} client library.
|
4
|
+
# HTTP Backend uses {https://github.com/httprb/http HTTP} client library.
|
5
5
|
class HTTP < Base
|
6
|
-
|
7
|
-
def get(endpoint, id, params={})
|
6
|
+
def get(endpoint, id, params = {})
|
8
7
|
response = ::HTTP
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
.timeout(global: timeout)
|
9
|
+
.headers(headers)
|
10
|
+
.get(template.expand(id: id, query: params, resource: endpoint).to_s)
|
12
11
|
serialize_response(response)
|
13
12
|
rescue ::HTTP::ConnectionError
|
14
13
|
raise Served::HTTPClient::ConnectionFailed.new(resource)
|
15
14
|
end
|
16
15
|
|
17
|
-
def put(endpoint, id, body, params={})
|
16
|
+
def put(endpoint, id, body, params = {})
|
18
17
|
response = ::HTTP
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
.timeout(global: timeout)
|
19
|
+
.headers(headers)
|
20
|
+
.put(template.expand(id: id,
|
21
|
+
query: params,
|
22
|
+
resource: endpoint).to_s,
|
23
|
+
body: body)
|
22
24
|
serialize_response(response)
|
23
25
|
rescue ::HTTP::ConnectionError
|
24
26
|
raise Served::HTTPClient::ConnectionFailed.new(resource)
|
25
27
|
end
|
26
28
|
|
27
|
-
def post(endpoint, body, params={})
|
29
|
+
def post(endpoint, body, params = {})
|
28
30
|
response = ::HTTP
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
.timeout(global: timeout)
|
32
|
+
.headers(headers)
|
33
|
+
.post(template.expand(query: params,
|
34
|
+
resource: endpoint).to_s,
|
35
|
+
body: body)
|
32
36
|
serialize_response(response)
|
33
37
|
rescue ::HTTP::ConnectionError
|
34
38
|
raise Served::HTTPClient::ConnectionFailed.new(resource)
|
35
39
|
end
|
36
40
|
|
37
|
-
def delete(endpoint, id, params={})
|
41
|
+
def delete(endpoint, id, params = {})
|
38
42
|
response = ::HTTP
|
39
|
-
|
40
|
-
|
41
|
-
|
43
|
+
.timeout(global: timeout)
|
44
|
+
.headers(headers)
|
45
|
+
.delete(template.expand(query: params,
|
46
|
+
resource: endpoint,
|
47
|
+
id: id).to_s)
|
42
48
|
serialize_response(response)
|
43
49
|
rescue ::HTTP::ConnectionError
|
44
50
|
raise Served::HTTPClient::ConnectionFailed.new(resource)
|
45
51
|
end
|
46
|
-
|
47
52
|
end
|
48
53
|
end
|
49
|
-
end
|
54
|
+
end
|
@@ -1,47 +1,49 @@
|
|
1
1
|
require 'httparty'
|
2
|
+
|
2
3
|
module Served
|
3
4
|
module Backends
|
4
|
-
# HTTParty Backend uses the
|
5
|
+
# HTTParty Backend uses the
|
6
|
+
# {https://github.com/jnunemaker/httparty HTTParty} client
|
5
7
|
class HTTParty < Base
|
6
|
-
|
7
|
-
|
8
|
-
|
8
|
+
def get(endpoint, id, params = {})
|
9
|
+
::HTTParty.get(template.expand(id: id,
|
10
|
+
query: params,
|
11
|
+
resource: endpoint).to_s,
|
9
12
|
headers: headers,
|
10
|
-
timeout: timeout
|
11
|
-
)
|
13
|
+
timeout: timeout)
|
12
14
|
rescue Errno::ECONNREFUSED
|
13
15
|
raise Served::HTTPClient::ConnectionFailed.new(resource)
|
14
16
|
end
|
15
17
|
|
16
|
-
def put(endpoint, id, body, params={})
|
17
|
-
::HTTParty.put(template.expand(id:
|
18
|
-
|
18
|
+
def put(endpoint, id, body, params = {})
|
19
|
+
::HTTParty.put(template.expand(id: id,
|
20
|
+
query: params,
|
21
|
+
resource: endpoint).to_s,
|
22
|
+
body: body,
|
19
23
|
headers: headers,
|
20
|
-
timeout: timeout
|
21
|
-
)
|
24
|
+
timeout: timeout)
|
22
25
|
rescue Errno::ECONNREFUSED
|
23
26
|
raise Served::HTTPClient::ConnectionFailed.new(resource)
|
24
27
|
end
|
25
28
|
|
26
|
-
def post(endpoint, body, params={})
|
29
|
+
def post(endpoint, body, params = {})
|
27
30
|
::HTTParty.post(template.expand(query: params, resource: endpoint).to_s,
|
28
31
|
body: body,
|
29
32
|
headers: headers,
|
30
|
-
timeout: timeout
|
31
|
-
)
|
33
|
+
timeout: timeout)
|
32
34
|
rescue Errno::ECONNREFUSED
|
33
35
|
raise Served::HTTPClient::ConnectionFailed.new(resource)
|
34
36
|
end
|
35
37
|
|
36
|
-
def delete(endpoint, id, params={})
|
37
|
-
::HTTParty.delete(template.expand(id:
|
38
|
+
def delete(endpoint, id, params = {})
|
39
|
+
::HTTParty.delete(template.expand(id: id,
|
40
|
+
query: params,
|
41
|
+
resource: endpoint).to_s,
|
38
42
|
headers: headers,
|
39
|
-
timeout: timeout
|
40
|
-
)
|
43
|
+
timeout: timeout)
|
41
44
|
rescue Errno::ECONNREFUSED
|
42
45
|
raise Served::HTTPClient::ConnectionFailed.new(resource)
|
43
46
|
end
|
44
|
-
|
45
47
|
end
|
46
48
|
end
|
47
|
-
end
|
49
|
+
end
|
@@ -1,45 +1,50 @@
|
|
1
1
|
require 'patron'
|
2
2
|
module Served
|
3
3
|
module Backends
|
4
|
-
# Patron Backend uses {Patron https://github.com/toland/patron} for its client.
|
5
|
-
#
|
4
|
+
# Patron Backend uses {Patron https://github.com/toland/patron} for its client.
|
5
|
+
# This backend does not lock the GIL and is thread safe.
|
6
|
+
# Use Patron if you need high concurrency.
|
6
7
|
class Patron < Base
|
7
|
-
|
8
|
-
def get(endpoint, id, params={})
|
8
|
+
def get(endpoint, id, params = {})
|
9
9
|
serialize_response(::Patron::Session.new(headers: headers, timeout: timeout)
|
10
|
-
.get(template.expand(id:
|
10
|
+
.get(template.expand(id: id,
|
11
|
+
query: params,
|
12
|
+
resource: endpoint).to_s))
|
11
13
|
rescue ::Patron::ConnectionFailed
|
12
14
|
raise Served::HTTPClient::ConnectionFailed.new(resource)
|
13
15
|
end
|
14
16
|
|
15
|
-
def put(endpoint, id, body, params={})
|
17
|
+
def put(endpoint, id, body, params = {})
|
16
18
|
serialize_response(::Patron::Session.new(headers: headers, timeout: timeout)
|
17
|
-
.put(template.expand(id:
|
19
|
+
.put(template.expand(id: id,
|
20
|
+
query: params,
|
21
|
+
resource: endpoint).to_s, body))
|
18
22
|
rescue ::Patron::ConnectionFailed
|
19
23
|
raise Served::HTTPClient::ConnectionFailed.new(resource)
|
20
24
|
end
|
21
25
|
|
22
|
-
def post(endpoint, body, params={})
|
26
|
+
def post(endpoint, body, params = {})
|
23
27
|
serialize_response(::Patron::Session.new(headers: headers, timeout: timeout)
|
24
|
-
.post(template.expand(query:
|
28
|
+
.post(template.expand(query: params,
|
29
|
+
resource: endpoint).to_s, body))
|
25
30
|
rescue ::Patron::ConnectionFailed
|
26
31
|
raise Served::HTTPClient::ConnectionFailed.new(resource)
|
27
32
|
end
|
28
33
|
|
29
|
-
def delete(endpoint, id, params={})
|
30
|
-
serialize_response(::Patron::Session.new(headers: headers,
|
31
|
-
|
34
|
+
def delete(endpoint, id, params = {})
|
35
|
+
serialize_response(::Patron::Session.new(headers: headers,
|
36
|
+
timeout: timeout)
|
37
|
+
.delete(template.expand(id: id,
|
38
|
+
query: params,
|
39
|
+
resource: endpoint).to_s))
|
32
40
|
rescue ::Patron::ConnectionFailed
|
33
41
|
raise Served::HTTPClient::ConnectionFailed.new(resource)
|
34
42
|
end
|
35
43
|
|
36
44
|
def serialize_response(response)
|
37
|
-
OpenStruct.new(
|
38
|
-
|
39
|
-
code: response.status
|
40
|
-
})
|
45
|
+
OpenStruct.new(body: response.body,
|
46
|
+
code: response.status)
|
41
47
|
end
|
42
|
-
|
43
48
|
end
|
44
49
|
end
|
45
|
-
end
|
50
|
+
end
|
data/lib/served/backends.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require_relative 'backends/base'
|
2
2
|
module Served
|
3
3
|
module Backends
|
4
|
-
|
5
4
|
# @private
|
6
5
|
def self.[](backend)
|
7
6
|
@backends ||= {
|
@@ -11,11 +10,10 @@ module Served
|
|
11
10
|
}
|
12
11
|
if @backends[backend]
|
13
12
|
require_relative "backends/#{backend}"
|
14
|
-
return
|
13
|
+
return const_get(@backends[backend].classify.to_sym)
|
15
14
|
end
|
16
15
|
require_relative 'backends/httparty'
|
17
|
-
|
16
|
+
const_get(@backends[:httparty].classify.to_sym)
|
18
17
|
end
|
19
|
-
|
20
18
|
end
|
21
|
-
end
|
19
|
+
end
|
data/lib/served/config.rb
CHANGED
data/lib/served/error.rb
CHANGED
data/lib/served/http_client.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'addressable/template'
|
2
2
|
require_relative 'error'
|
3
|
+
|
3
4
|
module Served
|
4
5
|
# Provides an interface between the HTTP client and the Resource.
|
5
6
|
class HTTPClient
|
6
|
-
|
7
|
-
DEFAULT_TEMPLATE = '{/resource*}{/id}.json{?query*}'
|
7
|
+
DEFAULT_TEMPLATE = '{/resource*}{/id}.json{?query*}'.freeze
|
8
8
|
|
9
9
|
attr_reader :template, :resource
|
10
10
|
|
@@ -12,12 +12,10 @@ module Served
|
|
12
12
|
delegate :headers, :timeout, :host, to: :@resource
|
13
13
|
|
14
14
|
class ConnectionFailed < Served::Error
|
15
|
-
|
16
|
-
|
17
|
-
super "Resource '#{resource.name}' could not be reached on '#{resource.host}'"
|
18
|
-
end
|
19
|
-
|
15
|
+
def initialize(resource)
|
16
|
+
super "Resource '#{resource.name}' could not be reached on '#{resource.host}'"
|
20
17
|
end
|
18
|
+
end
|
21
19
|
|
22
20
|
def initialize(resource)
|
23
21
|
@resource = resource
|
@@ -25,6 +23,5 @@ module Served
|
|
25
23
|
@template = Addressable::Template.new(h)
|
26
24
|
@backend = Served::Backends[Served.config.backend].new(self)
|
27
25
|
end
|
28
|
-
|
29
26
|
end
|
30
27
|
end
|
@@ -9,7 +9,6 @@ module Served
|
|
9
9
|
end
|
10
10
|
|
11
11
|
module ClassMethods
|
12
|
-
|
13
12
|
# declare an attribute for the resource
|
14
13
|
#
|
15
14
|
# @example
|
@@ -18,7 +17,7 @@ module Served
|
|
18
17
|
# end
|
19
18
|
#
|
20
19
|
# @param name [Symbol] the name of the attribute
|
21
|
-
def attribute(name, options={})
|
20
|
+
def attribute(name, options = {})
|
22
21
|
return if attributes.include?(name)
|
23
22
|
attributes[name] = options
|
24
23
|
attr_accessor name
|
@@ -39,20 +38,17 @@ module Served
|
|
39
38
|
end
|
40
39
|
|
41
40
|
module Prepend
|
42
|
-
|
43
41
|
def inherited(subclass)
|
44
|
-
|
42
|
+
attributes.each do |name, options|
|
45
43
|
subclass.attribute name, options
|
46
44
|
end
|
47
45
|
super
|
48
46
|
end
|
49
|
-
|
50
47
|
end
|
51
|
-
|
52
48
|
end
|
53
49
|
|
54
|
-
def initialize(hash={})
|
55
|
-
reload_with_attributes(normalize_keys(hash)
|
50
|
+
def initialize(hash = {})
|
51
|
+
reload_with_attributes(normalize_keys(hash))
|
56
52
|
self
|
57
53
|
end
|
58
54
|
|
@@ -102,7 +98,6 @@ module Served
|
|
102
98
|
params
|
103
99
|
end
|
104
100
|
end
|
105
|
-
|
106
101
|
end
|
107
102
|
end
|
108
103
|
end
|
data/lib/served/resource/base.rb
CHANGED
@@ -9,17 +9,20 @@ require_relative 'http_errors'
|
|
9
9
|
|
10
10
|
module Served
|
11
11
|
module Resource
|
12
|
-
# Service Resources should inherit directly from this class. Provides
|
13
|
-
# services based on the namespace.
|
14
|
-
#
|
15
|
-
#
|
12
|
+
# Service Resources should inherit directly from this class. Provides
|
13
|
+
# interfaces necessary for communicating with services based on the namespace.
|
14
|
+
# Classes should be namespaced under Services::ServiceName where ServiceName is
|
15
|
+
# the name of the service the resource lives on. The resource determines the
|
16
|
+
# host of the service based on this this namespace and what is in the
|
17
|
+
# configuration.
|
16
18
|
#
|
17
|
-
# Service Resources supports some ActiveModel validations so that a developer can
|
18
|
-
# if desired. Validation options can be passed
|
19
|
-
# ActiveModel#validate
|
19
|
+
# Service Resources supports some ActiveModel validations so that a developer can
|
20
|
+
# include client side validations if desired. Validation options can be passed
|
21
|
+
# to the #attribute class method using the same options as ActiveModel#validate.
|
20
22
|
#
|
21
|
-
# A resource may also serialize values as specific classes, including nested
|
22
|
-
# Served Resource, it will validate the
|
23
|
+
# A resource may also serialize values as specific classes, including nested
|
24
|
+
# resources. If serialize is set to a Served Resource, it will validate the
|
25
|
+
# nested resource as well as the top level.
|
23
26
|
class Base
|
24
27
|
include Configurable
|
25
28
|
include Requestable
|
@@ -28,7 +31,6 @@ module Served
|
|
28
31
|
include Serializable
|
29
32
|
|
30
33
|
attribute :id
|
31
|
-
|
32
34
|
end
|
33
35
|
end
|
34
36
|
end
|
@@ -8,9 +8,7 @@ module Served
|
|
8
8
|
end
|
9
9
|
|
10
10
|
module ClassMethods
|
11
|
-
|
12
11
|
module Prepend
|
13
|
-
|
14
12
|
private
|
15
13
|
|
16
14
|
def inherited(subclass)
|
@@ -18,25 +16,24 @@ module Served
|
|
18
16
|
instance_variables.each do |v|
|
19
17
|
instance = instance_variable_get(v)
|
20
18
|
instance = instance.clone unless instance.is_a? Fixnum
|
21
|
-
subclass.send(:instance_variable_set, v, instance) if /@_c_/
|
19
|
+
subclass.send(:instance_variable_set, v, instance) if v.to_s =~ /@_c_/
|
22
20
|
end
|
23
21
|
end
|
24
|
-
|
25
22
|
end
|
26
23
|
|
27
24
|
private
|
28
25
|
|
29
26
|
# Declare a configurable attribute. This is used to declare the configuration methods used in
|
30
27
|
# Served::Resource::Base
|
31
|
-
def class_configurable(name, options={}, &block)
|
28
|
+
def class_configurable(name, options = {}, &block)
|
32
29
|
instance_eval do
|
33
30
|
instance_variable_set(:"@_c_#{name}", options[:default]) if options[:default]
|
34
|
-
instance_variable_set(:"@_c_#{name}", block
|
31
|
+
instance_variable_set(:"@_c_#{name}", block) if block_given? && !instance_variable_get(:"@#{name}")
|
35
32
|
|
36
|
-
define_singleton_method(name) do |value=nil|
|
33
|
+
define_singleton_method(name) do |value = nil|
|
37
34
|
instance_variable_set(:"@_c_#{name}", value) if value
|
38
35
|
value = instance_variable_get(:"@_c_#{name}") unless value
|
39
|
-
return instance_eval
|
36
|
+
return instance_eval(&value) if value.is_a? Proc
|
40
37
|
value
|
41
38
|
end
|
42
39
|
|
@@ -45,7 +42,6 @@ module Served
|
|
45
42
|
end
|
46
43
|
end
|
47
44
|
end
|
48
|
-
|
49
45
|
end
|
50
46
|
end
|
51
47
|
end
|
@@ -5,6 +5,7 @@ module Served
|
|
5
5
|
attr_reader :server_backtrace
|
6
6
|
attr_reader :errors
|
7
7
|
attr_reader :response
|
8
|
+
attr_reader :code
|
8
9
|
|
9
10
|
# Defined in individual error classes
|
10
11
|
def self.code
|
@@ -29,114 +30,83 @@ module Served
|
|
29
30
|
def status
|
30
31
|
self.class.status
|
31
32
|
end
|
32
|
-
|
33
|
-
def code
|
34
|
-
@code
|
35
|
-
end
|
36
|
-
|
37
33
|
end
|
38
34
|
|
39
35
|
# 301 MovedPermanently
|
40
36
|
class MovedPermanently < HttpError
|
41
|
-
|
42
37
|
def self.code
|
43
38
|
301
|
44
39
|
end
|
45
|
-
|
46
40
|
end
|
47
41
|
|
48
42
|
# 400 BadRequest
|
49
43
|
class BadRequest < HttpError
|
50
|
-
|
51
44
|
def self.code
|
52
45
|
400
|
53
46
|
end
|
54
|
-
|
55
47
|
end
|
56
48
|
|
57
49
|
# 401 Unauthorized
|
58
50
|
class Unauthorized < HttpError
|
59
|
-
|
60
51
|
def self.code
|
61
52
|
401
|
62
53
|
end
|
63
|
-
|
64
54
|
end
|
65
55
|
|
66
56
|
# 403 Forbidden
|
67
57
|
class Forbidden < HttpError
|
68
|
-
|
69
58
|
def self.code
|
70
59
|
403
|
71
60
|
end
|
72
|
-
|
73
61
|
end
|
74
62
|
|
75
63
|
# 404 NotFound
|
76
64
|
class NotFound < HttpError
|
77
|
-
|
78
65
|
def self.code
|
79
66
|
404
|
80
67
|
end
|
81
|
-
|
82
68
|
end
|
83
69
|
|
84
70
|
# 405 MethodNotAllowed
|
85
71
|
class MethodNotAllowed < HttpError
|
86
|
-
|
87
72
|
def self.code
|
88
73
|
405
|
89
74
|
end
|
90
|
-
|
91
75
|
end
|
92
76
|
|
93
77
|
# 406 NotAcceptable
|
94
78
|
class NotAcceptable < HttpError
|
95
|
-
|
96
79
|
def self.code
|
97
80
|
406
|
98
81
|
end
|
99
|
-
|
100
82
|
end
|
101
83
|
|
102
84
|
# 408 RequestTimeout
|
103
85
|
class RequestTimeout < HttpError
|
104
|
-
|
105
86
|
def self.code
|
106
87
|
408
|
107
88
|
end
|
108
|
-
|
109
89
|
end
|
110
90
|
|
111
91
|
# 422 UnprocessableEntity
|
112
92
|
class UnprocessableEntity < HttpError
|
113
|
-
|
114
93
|
def self.code
|
115
94
|
422
|
116
95
|
end
|
117
|
-
|
118
96
|
end
|
119
97
|
|
120
98
|
# 500 InternalServerError
|
121
99
|
class InternalServerError < HttpError
|
122
|
-
|
123
100
|
def self.code
|
124
101
|
500
|
125
102
|
end
|
126
|
-
|
127
103
|
end
|
128
104
|
|
129
105
|
# 503 BadGateway
|
130
106
|
class BadGateway < HttpError
|
131
|
-
|
132
107
|
def self.code
|
133
108
|
503
|
134
109
|
end
|
135
|
-
|
136
110
|
end
|
137
|
-
|
138
111
|
end
|
139
112
|
end
|
140
|
-
|
141
|
-
|
142
|
-
|
@@ -5,14 +5,12 @@ module Served
|
|
5
5
|
|
6
6
|
# raised when a handler is defined if the method doesn't exist or if a proc isn't supplied
|
7
7
|
class HandlerRequired < StandardError
|
8
|
-
|
9
8
|
def initialize
|
10
9
|
super 'a handler is required, it must be a proc or a valid method'
|
11
10
|
end
|
12
|
-
|
13
11
|
end
|
14
12
|
|
15
|
-
HEADERS = { 'Content-type' => 'application/json', 'Accept' => 'application/json' }
|
13
|
+
HEADERS = { 'Content-type' => 'application/json', 'Accept' => 'application/json' }.freeze
|
16
14
|
|
17
15
|
included do
|
18
16
|
include Configurable
|
@@ -30,7 +28,7 @@ module Served
|
|
30
28
|
end
|
31
29
|
|
32
30
|
class_configurable :_headers do
|
33
|
-
HEADERS
|
31
|
+
HEADERS.dup
|
34
32
|
end
|
35
33
|
|
36
34
|
class_configurable :handlers, default: {}
|
@@ -60,12 +58,9 @@ module Served
|
|
60
58
|
# 500 level errors
|
61
59
|
handle(500) { Resource::InternalServerError }
|
62
60
|
handle(503) { Resource::BadGateway }
|
63
|
-
|
64
|
-
|
65
61
|
end
|
66
62
|
|
67
63
|
module ClassMethods
|
68
|
-
|
69
64
|
def handle_response(response)
|
70
65
|
if raise_on_exceptions
|
71
66
|
handler = handlers[response.code]
|
@@ -91,12 +86,12 @@ module Served
|
|
91
86
|
# the specific response code has been called. The method or proc should return a hash of attributes, if an
|
92
87
|
# error class is returned it will be raised
|
93
88
|
# @yieldreturn [Hash] a hash of attributes, if an error class is returned it will be raised
|
94
|
-
def handle(code_or_range, symbol_or_proc=nil, &block)
|
89
|
+
def handle(code_or_range, symbol_or_proc = nil, &block)
|
95
90
|
raise HandlerRequired unless symbol_or_proc || block_given?
|
96
91
|
if code_or_range.is_a?(Range) || code_or_range.is_a?(Array)
|
97
|
-
code_or_range.each
|
92
|
+
code_or_range.each do |c|
|
98
93
|
handlers[c] = symbol_or_proc || block
|
99
|
-
|
94
|
+
end
|
100
95
|
else
|
101
96
|
handlers[code_or_range] = symbol_or_proc || block
|
102
97
|
end
|
@@ -106,13 +101,14 @@ module Served
|
|
106
101
|
#
|
107
102
|
# @param headers [Hash] the headers to send with each requesat
|
108
103
|
# @return headers [Hash] the default headers for the class
|
109
|
-
def headers(h={})
|
104
|
+
def headers(h = {})
|
110
105
|
headers ||= _headers
|
111
106
|
_headers(headers.merge!(h)) unless h.empty?
|
112
107
|
_headers
|
113
108
|
end
|
114
109
|
|
115
|
-
# Looks up a resource on the service by id. For example
|
110
|
+
# Looks up a resource on the service by id. For example,
|
111
|
+
# `SomeResource.find(5)` would call `/some_resources/5`
|
116
112
|
#
|
117
113
|
# @param id [Integer] the id of the resource
|
118
114
|
# @return [Resource::Base] the resource object.
|
@@ -135,8 +131,8 @@ module Served
|
|
135
131
|
end
|
136
132
|
end
|
137
133
|
|
138
|
-
# Saves the record to the service. Will call POST if the record does not
|
139
|
-
# to update the record
|
134
|
+
# Saves the record to the service. Will call POST if the record does not
|
135
|
+
# have an id, otherwise will call PUT to update the record
|
140
136
|
#
|
141
137
|
# @return [Boolean] returns true or false depending on save success
|
142
138
|
def save
|
@@ -169,15 +165,15 @@ module Served
|
|
169
165
|
self.class.get(id, params)
|
170
166
|
end
|
171
167
|
|
172
|
-
def put(params={})
|
168
|
+
def put(params = {})
|
173
169
|
handle_response(client.put(resource_name, id, dump, params))
|
174
170
|
end
|
175
171
|
|
176
|
-
def post(params={})
|
172
|
+
def post(params = {})
|
177
173
|
handle_response(client.post(resource_name, dump, params))
|
178
174
|
end
|
179
175
|
|
180
|
-
def delete(params={})
|
176
|
+
def delete(params = {})
|
181
177
|
response = client.delete(resource_name, id, params)
|
182
178
|
return true if response.code == 204
|
183
179
|
|
@@ -1,13 +1,15 @@
|
|
1
1
|
module Served
|
2
2
|
module Resource
|
3
3
|
class ResponseInvalid < Served::Error
|
4
|
+
def initialize(resource, original_error = false)
|
5
|
+
if original_error
|
6
|
+
return super "The resource '#{resource.name}' failed to serialize the " \
|
7
|
+
"response with message: #{original_error.message}'"
|
8
|
+
end
|
4
9
|
|
5
|
-
|
6
|
-
|
7
|
-
"'#{orignal_error.message}'" if orignal_error
|
8
|
-
super "The resource '#{resource.name}' returned a response, but the result of serialization was `nil`"
|
10
|
+
super "The resource '#{resource.name}' returned a response, but the result " \
|
11
|
+
"of serialization was `nil`"
|
9
12
|
end
|
10
|
-
|
11
13
|
end
|
12
14
|
end
|
13
|
-
end
|
15
|
+
end
|
@@ -8,7 +8,7 @@ module Served
|
|
8
8
|
|
9
9
|
# pseudo boolean class for serialization
|
10
10
|
unless Object.const_defined?(:Boolean)
|
11
|
-
class ::Boolean
|
11
|
+
class ::Boolean
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
@@ -21,7 +21,6 @@ module Served
|
|
21
21
|
end
|
22
22
|
|
23
23
|
module ClassMethods
|
24
|
-
|
25
24
|
def load(string)
|
26
25
|
begin
|
27
26
|
result = serializer.load(self, string)
|
@@ -56,17 +55,24 @@ module Served
|
|
56
55
|
true
|
57
56
|
end
|
58
57
|
end
|
59
|
-
|
60
|
-
|
61
|
-
|
58
|
+
|
59
|
+
if type.ancestors.include?(Served::Resource::Base) ||
|
60
|
+
type.ancestors.include?(Served::Attribute::Base)
|
61
|
+
return ->(v) { type.new(v) }
|
62
|
+
end
|
63
|
+
|
64
|
+
raise InvalidAttributeSerializer.new(type)
|
62
65
|
end
|
63
66
|
|
64
67
|
def serialize_attribute(attr, value)
|
65
68
|
return false unless attributes[attr.to_sym]
|
66
69
|
serializer = attribute_serializer_for(attributes[attr.to_sym][:serialize])
|
67
70
|
if value.is_a? Array
|
68
|
-
# TODO: Remove the Array class check below in 1.0, only here
|
69
|
-
|
71
|
+
# TODO: Remove the Array class check below in 1.0, only here
|
72
|
+
# for backwards compatibility
|
73
|
+
return value if attributes[attr.to_sym][:serialize].nil? ||
|
74
|
+
attributes[attr.to_sym][:serialize] == Array
|
75
|
+
|
70
76
|
value.collect do |v|
|
71
77
|
if v.is_a? attributes[attr.to_sym][:serialize]
|
72
78
|
v
|
@@ -78,10 +84,9 @@ module Served
|
|
78
84
|
serializer.call(value)
|
79
85
|
end
|
80
86
|
end
|
81
|
-
|
82
87
|
end
|
83
88
|
|
84
|
-
def to_json(*
|
89
|
+
def to_json(*_args)
|
85
90
|
dump
|
86
91
|
end
|
87
92
|
|
@@ -6,15 +6,18 @@ module Served
|
|
6
6
|
|
7
7
|
# Supported Validation Types
|
8
8
|
SUPPORTED_VALIDATIONS = [
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
]
|
9
|
+
:presence,
|
10
|
+
:numericality,
|
11
|
+
:format,
|
12
|
+
:inclusion
|
13
|
+
].freeze
|
14
14
|
|
15
|
-
|
15
|
+
# Saves a resource and raises an error if the save fails.
|
16
16
|
def save!
|
17
|
-
|
17
|
+
unless run_validations! && save(false)
|
18
|
+
raise ::Served::Resource::ResourceInvalid.new(self)
|
19
|
+
end
|
20
|
+
|
18
21
|
true
|
19
22
|
end
|
20
23
|
|
@@ -31,9 +34,8 @@ module Served
|
|
31
34
|
end
|
32
35
|
|
33
36
|
module Prepend
|
34
|
-
|
35
|
-
|
36
|
-
return false if (with_validations && self.class.validate_on_save && !valid?)
|
37
|
+
def save(with_validations = true)
|
38
|
+
return false if with_validations && self.class.validate_on_save && !valid?
|
37
39
|
super()
|
38
40
|
end
|
39
41
|
|
@@ -47,18 +49,14 @@ module Served
|
|
47
49
|
end
|
48
50
|
errors.empty?
|
49
51
|
end
|
50
|
-
|
51
52
|
end
|
52
53
|
|
53
54
|
module ClassMethods
|
54
|
-
|
55
55
|
module Prepend
|
56
|
-
|
57
|
-
def attribute(name, options={})
|
56
|
+
def attribute(name, options = {})
|
58
57
|
super
|
59
58
|
set_validations_for_attribute(name, options)
|
60
59
|
end
|
61
|
-
|
62
60
|
end
|
63
61
|
|
64
62
|
private
|
@@ -69,9 +67,7 @@ module Served
|
|
69
67
|
validates name, validation => options[validation] if options[validation]
|
70
68
|
end
|
71
69
|
end
|
72
|
-
|
73
70
|
end
|
74
|
-
|
75
71
|
end
|
76
72
|
end
|
77
73
|
end
|
@@ -1,32 +1,32 @@
|
|
1
1
|
require 'json'
|
2
2
|
module Served
|
3
3
|
module Serializers
|
4
|
-
|
5
|
-
#
|
4
|
+
# The default serializer assumes that the default Rails API response
|
5
|
+
# is used for both data and errors.
|
6
6
|
module Json
|
7
|
-
|
8
7
|
def self.load(resource, data)
|
9
8
|
parsed = JSON.parse(data)
|
10
9
|
# assume we need to return the entire response if it isn't
|
11
|
-
# namespaced by keys. TODO: remove after 1.0, this is strictly
|
10
|
+
# namespaced by keys. TODO: remove after 1.0, this is strictly
|
11
|
+
# for backwards compatibility
|
12
12
|
resource_name = resource.resource_name
|
13
13
|
if resource_name.is_a? Array
|
14
|
-
warn '[DEPRECATION] passing an array for resource name will no longer
|
15
|
-
|
16
|
-
|
14
|
+
warn '[DEPRECATION] passing an array for resource name will no longer ' \
|
15
|
+
'be supported in Served 1.0, please ensure a single string is ' \
|
16
|
+
'returned instead'
|
17
|
+
resource_name = resource_name.last # backwards compatibility
|
17
18
|
end
|
18
19
|
parsed[resource_name.singularize] || parsed
|
19
20
|
end
|
20
21
|
|
21
22
|
def self.dump(resource, attributes)
|
22
|
-
a = Hash[attributes.collect { |k,v| v.blank? ? nil : [k,v] }.compact]
|
23
|
-
{resource.resource_name.singularize => a}.to_json
|
23
|
+
a = Hash[attributes.collect { |k, v| v.blank? ? nil : [k, v] }.compact]
|
24
|
+
{ resource.resource_name.singularize => a }.to_json
|
24
25
|
end
|
25
26
|
|
26
27
|
def self.exception(data)
|
27
28
|
JSON.parse(data)
|
28
29
|
end
|
29
|
-
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
@@ -20,7 +20,8 @@ module Served
|
|
20
20
|
|
21
21
|
def self.parse_errors(result, resource)
|
22
22
|
result.each do |error|
|
23
|
-
if error.source_parameter &&
|
23
|
+
if error.source_parameter &&
|
24
|
+
resource.attributes.keys.include?(error.source_parameter.to_sym)
|
24
25
|
resource.errors.add(error.source_parameter.to_sym, error_message(error))
|
25
26
|
else
|
26
27
|
resource.errors.add(:base, error_message(error))
|
@@ -73,7 +74,9 @@ module Served
|
|
73
74
|
rel_data = rel['data']
|
74
75
|
|
75
76
|
relationship_attributes = if rel_data.is_a?(Array)
|
76
|
-
rel_data.inject([])
|
77
|
+
rel_data.inject([]) do |ary, r|
|
78
|
+
ary << restructure_relationship(r, included)
|
79
|
+
end
|
77
80
|
else
|
78
81
|
restructure_relationship(rel_data, included)
|
79
82
|
end
|
@@ -88,7 +91,10 @@ module Served
|
|
88
91
|
end
|
89
92
|
|
90
93
|
def self.restructure_relationship(resource, included)
|
91
|
-
relationship = included.find
|
94
|
+
relationship = included.find do |r|
|
95
|
+
resource['id'] == r['id'] && resource['type'] == r['type']
|
96
|
+
end
|
97
|
+
|
92
98
|
relationship['attributes'].merge('id' => resource['id']) if relationship
|
93
99
|
end
|
94
100
|
end
|
data/lib/served/version.rb
CHANGED
data/served.gemspec
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
|
2
3
|
lib = File.expand_path('../lib', __FILE__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require 'served/version'
|
@@ -9,8 +10,8 @@ Gem::Specification.new do |spec|
|
|
9
10
|
spec.authors = ['Jarod Reid']
|
10
11
|
spec.email = ['jarod@solidalchemy.com']
|
11
12
|
|
12
|
-
spec.summary =
|
13
|
-
spec.description =
|
13
|
+
spec.summary = 'Served provides an easy to use model layer for communicating with disributed Rails based Services.'
|
14
|
+
spec.description = 'Served provides an easy to use model layer for communicating with disributed Rails based Services.'
|
14
15
|
spec.homepage = 'http://github.com/fugufish/served'
|
15
16
|
spec.license = 'MIT'
|
16
17
|
|
@@ -21,7 +22,7 @@ Gem::Specification.new do |spec|
|
|
21
22
|
|
22
23
|
spec.add_dependency 'activesupport', '>= 3.2'
|
23
24
|
spec.add_dependency 'addressable', '>= 2.4.0'
|
24
|
-
spec.add_dependency 'activemodel',
|
25
|
+
spec.add_dependency 'activemodel', '>= 3.2'
|
25
26
|
|
26
27
|
spec.add_development_dependency 'httparty', '~> 0.14.0'
|
27
28
|
spec.add_development_dependency 'bundler', '~> 1.10'
|
@@ -29,5 +30,5 @@ Gem::Specification.new do |spec|
|
|
29
30
|
spec.add_development_dependency 'rspec', '~> 3.4.0'
|
30
31
|
spec.add_development_dependency 'http', '~> 1.0.4'
|
31
32
|
spec.add_development_dependency 'patron', '~> 0.5.0'
|
32
|
-
|
33
|
+
spec.add_development_dependency 'rubocop', '~> 0.49'
|
33
34
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: served
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jarod Reid
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-06-
|
11
|
+
date: 2017-06-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -136,6 +136,20 @@ dependencies:
|
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: 0.5.0
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rubocop
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0.49'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0.49'
|
139
153
|
description: Served provides an easy to use model layer for communicating with disributed
|
140
154
|
Rails based Services.
|
141
155
|
email:
|
@@ -146,6 +160,7 @@ extra_rdoc_files: []
|
|
146
160
|
files:
|
147
161
|
- ".gitignore"
|
148
162
|
- ".rspec"
|
163
|
+
- ".rubocop.yml"
|
149
164
|
- ".ruby-version"
|
150
165
|
- ".travis.yml"
|
151
166
|
- CHANGELOG.md
|
@@ -205,12 +220,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
205
220
|
version: '0'
|
206
221
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
207
222
|
requirements:
|
208
|
-
- - "
|
223
|
+
- - ">"
|
209
224
|
- !ruby/object:Gem::Version
|
210
|
-
version:
|
225
|
+
version: 1.3.1
|
211
226
|
requirements: []
|
212
227
|
rubyforge_project:
|
213
|
-
rubygems_version: 2.6.
|
228
|
+
rubygems_version: 2.6.8
|
214
229
|
signing_key:
|
215
230
|
specification_version: 4
|
216
231
|
summary: Served provides an easy to use model layer for communicating with disributed
|