easy-api 0.2.3 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e7a7b501b68e2d27078a346db4d2e9ccd369c227
4
- data.tar.gz: 4c9343aac20833e366a9e62d213457f9c1e76e47
3
+ metadata.gz: 94b5b22c8b02c19de08ca14585473511abbf81d4
4
+ data.tar.gz: 73a7eaadbdc4601a5fbf1b92275aef5103765fa1
5
5
  SHA512:
6
- metadata.gz: 24a3a204a78387f1571f66f832c4b343b5c1b5786b3fac965449b514da09bab49ae71a9bb0d35e1c7cf56e9ebb12d2663be60545501e34bcc0a95d983a7a2f85
7
- data.tar.gz: e98d3bc861219153d22ef088100079c1346e75dd7273b14ba2a5a12a9abf6de6bdb5e6971d4f53df7a1a9673e8f3d10431ec3fbdb8891799ee72ecfdc7e85842
6
+ metadata.gz: 5fab722ebc87aca767b53bab435d31d968bf9c3f43666052e962df18a1ea78c89ff7766c86d45acfa0eb25f1c559e10b2de272d9cf5bd0fa53765cb46241f6a2
7
+ data.tar.gz: 78242156bbe9579e5553e1fdba48fc4383b36f9e979ac766409e49221532a083cc6dd2464ece1ba2ea95cc400985306a0c51fb8de5242b93accdf839d44fa2a4
@@ -1,3 +1,7 @@
1
+ # EasyAPI 0.3.0 (December 18, 2015) #
2
+
3
+ * Add support for externally generated JSON and XML
4
+
1
5
  # EasyAPI 0.2.3 (August 28, 2015) #
2
6
 
3
7
  * Allow Easy::Api:Error.codes and Easy::Api:Error.messages to be added to
@@ -0,0 +1,5 @@
1
+ guard :rspec, cmd: 'rspec', all_after_pass: true, all_on_start: true do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
data/README.md CHANGED
@@ -83,9 +83,40 @@ If your API supports callbacks (JSONP) these can also be passed. The returned co
83
83
 
84
84
  api.render_result(format: params[:format], callback: params[:callback])
85
85
 
86
+ ## Support for externally generated JSON and XML
87
+
88
+ Sometimes it makes sense to use your database to generate the raw JSON or XML. If
89
+ you need to do this, you can use the raw method as shown below.
90
+
91
+ easy_api do |api|
92
+ api.status_code = 200
93
+ api.success = true
94
+ api.year = 2015
95
+ api.raw.animals = '[{"name" => "Charles Bird"}, {"name" => "Silver"}, {"name" => "Lassie"}]'
96
+
97
+ api.render_result(format: params[:format])
98
+ end
99
+
100
+ or support both JSON and XML:
101
+
102
+ easy_api do |api|
103
+ api.status_code = 200
104
+ api.success = true
105
+ api.enterprise = 'safe'
106
+
107
+ if params[:format] == 'xml'
108
+ api.raw.categories = '<category>Large</category><category>Medium</category><category>Small</category>'
109
+ else
110
+ api.raw.categories = '["Large", "Medium", "Small"]'
111
+ end
112
+
113
+ api.render_result(format: params[:format])
114
+ end
115
+
116
+
86
117
  ### Using Easy::Api::ControllerMethods
87
118
 
88
- **Depricated**
119
+ **Deprecated**
89
120
 
90
121
  Add the following line to all Api Controllers:
91
122
 
@@ -23,4 +23,5 @@ Gem::Specification.new do |gem|
23
23
  gem.add_development_dependency 'pry'
24
24
  gem.add_development_dependency 'rspec', '>= 2.14'
25
25
  gem.add_development_dependency 'rspec-rails'
26
+ gem.add_development_dependency 'guard-rspec', '~> 4.6'
26
27
  end
@@ -21,7 +21,7 @@ module Easy::Api::ControllerMethods
21
21
  content_type = 'application/json'
22
22
  end
23
23
 
24
- render :json => @result, :status => status, :callback => params[:callback], :content_type => content_type
24
+ render :json => @result.to_json, :status => status, :callback => params[:callback], :content_type => content_type
25
25
  end
26
26
  end
27
27
  end
@@ -8,9 +8,14 @@ module Easy::Api
8
8
  # #status_code
9
9
  # success
10
10
  # error (see Easy::Api::Error#new)
11
- class Result < OpenStruct
11
+ class Result
12
+
12
13
  attr_writer :success, :status_code, :error
13
14
 
15
+ def initialize
16
+ @native_attributes = {}
17
+ end
18
+
14
19
  # An instance of Easy::Api::Error or nil if there is no error
15
20
  # @return [Easy::Api::Error, nil]
16
21
  def error
@@ -30,12 +35,26 @@ module Easy::Api
30
35
  @status_code || raise("Easy::Api::Result needs a status_code!")
31
36
  end
32
37
 
33
- # Used by Rails to render the result as json
34
- #
35
- # Will always contain 'success', the error if there is one, and any dynamic attributes.
36
- # @return [Hash]
37
- def as_json(options={})
38
- convert_to_hash
38
+ def raw
39
+ @raw ||= RawAttributesResult.new
40
+ end
41
+
42
+ def to_json(options={})
43
+ json = non_raw_attributes.to_json
44
+
45
+ if raw.attributes.any?
46
+ json = json.chop # remove the closing '}'
47
+
48
+ raw.attributes.each_with_index do |(attr_name, raw_value), index|
49
+ json << ','
50
+
51
+ json << '"' << attr_name << '":' << raw_value
52
+ end
53
+
54
+ json << '}'
55
+ end
56
+
57
+ json
39
58
  end
40
59
 
41
60
  # Used by Rails to parse the result as xml
@@ -46,15 +65,58 @@ module Easy::Api
46
65
  options = options.dup
47
66
  options[:root] ||= 'response'
48
67
  options[:skip_types] ||= true
49
- convert_to_hash.to_xml(options)
68
+
69
+ xml = non_raw_attributes.to_xml(options)
70
+
71
+ if raw.attributes.any?
72
+ xml.gsub!(/<\/#{options[:root]}>[\s\n]*\z/, '') # remove the closing </response>
73
+
74
+ raw.attributes.each_with_index do |(attr_name, raw_value), index|
75
+ xml << '<' << attr_name << '>' << raw_value << '</' << attr_name << '>'
76
+ end
77
+
78
+ xml << "</#{options[:root]}>"
79
+ end
80
+
81
+ xml
82
+ end
83
+
84
+ def method_missing(symbol, *args)
85
+ if symbol =~ /.+=/
86
+ attr_name = symbol.to_s[0..-2]
87
+ @native_attributes[attr_name] = args.first
88
+ else
89
+ super
90
+ end
50
91
  end
51
92
 
52
93
  private
53
94
 
54
- def convert_to_hash
55
- hash = marshal_dump.merge(:success => success)
56
- hash[:error] = error unless error.nil?
95
+ def non_raw_attributes
96
+ hash = @native_attributes.merge('success' => success)
97
+
98
+ if error
99
+ hash['error'] = error.as_json
100
+ end
101
+
57
102
  hash
58
103
  end
59
104
  end
105
+
106
+ class RawAttributesResult
107
+ def initialize
108
+ @attributes = {}
109
+ end
110
+
111
+ attr_reader :attributes
112
+
113
+ def method_missing(symbol, *args)
114
+ if symbol =~ /.+=/
115
+ attr_name = symbol.to_s[0..-2]
116
+ @attributes[attr_name] = args.first
117
+ else
118
+ super
119
+ end
120
+ end
121
+ end
60
122
  end
@@ -1,5 +1,5 @@
1
1
  module Easy
2
2
  module Api
3
- VERSION = "0.2.3"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  end
@@ -1,9 +1,10 @@
1
1
  require 'spec_helper'
2
+ require 'json'
2
3
 
3
4
  describe Easy::Api::Result do
4
- describe "#as_json" do
5
+ describe "#to_json" do
5
6
  let(:result) { Easy::Api::Result.new }
6
- subject { result.as_json }
7
+ subject(:parsed_json) { JSON.parse(result.to_json) }
7
8
 
8
9
  context "when result is unsuccessful" do
9
10
  let(:api_error) { Easy::Api::Error.new(:unauthorized) }
@@ -12,65 +13,110 @@ describe Easy::Api::Result do
12
13
  result.error = api_error
13
14
  end
14
15
 
16
+ it "contain the expected values" do
17
+ expect(parsed_json).to eq({'success' => false, 'error' => {'code' => 401, 'message' => 'Unauthorized request'}})
18
+ end
19
+ end
20
+
21
+ context "when result is successful" do
22
+
23
+ before do
24
+ result.success = true
25
+ result.customer = "Bob Loblaw"
26
+ end
27
+
15
28
  it "has a success key" do
16
- expect(subject).to have_key(:success)
29
+ expect(subject).to have_key('success')
30
+ end
31
+
32
+ it "is successful" do
33
+ expect(subject['success']).to be(true)
34
+ end
35
+
36
+ it "has a customer key" do
37
+ expect(subject).to have_key('customer')
17
38
  end
18
39
 
19
- it "is not successful" do
20
- expect(subject[:success]).to be(false)
40
+ it "has a customer name" do
41
+ expect(subject['customer']).to eql "Bob Loblaw"
21
42
  end
22
43
 
23
44
  it "has no status code" do
24
- expect(subject).to_not have_key(:status_code)
45
+ expect(subject).to_not have_key('status_code')
25
46
  end
47
+ end
48
+ end
26
49
 
27
- it "has an error" do
28
- expect(subject).to have_key(:error)
50
+ describe '#to_json' do
51
+ let(:result) { Easy::Api::Result.new }
52
+
53
+ subject(:parsed_json) { JSON.parse(result.to_json) }
54
+
55
+ context 'with basic result attributes' do
56
+ before do
57
+ result.success = true
58
+ result.customer = "Bert O'Malley"
29
59
  end
30
60
 
31
- context "json error" do
32
- subject { result.as_json[:error] }
61
+ it "has a success key" do
62
+ expect(parsed_json).to have_key('success')
63
+ end
33
64
 
34
- it "has an error" do
35
- expect(subject.code).to eql api_error.code
36
- end
65
+ it "is successful" do
66
+ expect(parsed_json['success']).to be(true)
67
+ end
37
68
 
38
- it "has an error code" do
39
- expect(subject.message).to eql api_error.message
40
- end
69
+ it "has a customer key" do
70
+ expect(parsed_json).to have_key('customer')
71
+ end
41
72
 
73
+ it "has a customer name" do
74
+ expect(parsed_json['customer']).to eql "Bert O'Malley"
42
75
  end
43
76
  end
44
77
 
45
- context "when result is successful" do
46
-
78
+ context 'with some RAW json attributes' do
47
79
  before do
48
80
  result.success = true
49
- result.customer = "Bob Loblaw"
81
+ result.raw.customer = '{"name":"Geoff Flinders","age":27,"height": 1.79}'
50
82
  end
51
83
 
52
84
  it "has a success key" do
53
- expect(subject).to have_key(:success)
85
+ expect(parsed_json).to have_key('success')
54
86
  end
55
87
 
56
88
  it "is successful" do
57
- expect(subject[:success]).to be(true)
89
+ expect(parsed_json['success']).to be(true)
58
90
  end
59
91
 
60
92
  it "has a customer key" do
61
- expect(subject).to have_key(:customer)
93
+ expect(parsed_json).to have_key('customer')
62
94
  end
63
95
 
64
- it "has a customer name" do
65
- expect(subject[:customer]).to eql "Bob Loblaw"
96
+ it "has a customer name key" do
97
+ expect(parsed_json['customer']).to have_key('name')
66
98
  end
67
99
 
68
- it "has no status code" do
69
- expect(subject).to_not have_key(:status_code)
100
+ it "has a customer name value" do
101
+ expect(parsed_json['customer']['name']).to eq('Geoff Flinders')
70
102
  end
71
103
 
72
- end
104
+ it "has a customer age key" do
105
+ expect(parsed_json['customer']).to have_key('name')
106
+ end
73
107
 
108
+ it "has a customer age value" do
109
+ expect(parsed_json['customer']['age']).to eq(27)
110
+ end
111
+
112
+ it "has a customer height key" do
113
+ expect(parsed_json['customer']).to have_key('height')
114
+ end
115
+
116
+ it "has a customer height value" do
117
+ expect(parsed_json['customer']['height']).to eq(1.79)
118
+ end
119
+ end
74
120
  end
75
121
 
76
122
  describe "#status_code" do
@@ -95,9 +141,8 @@ describe Easy::Api::Result do
95
141
  end
96
142
 
97
143
  describe "#to_xml" do
98
-
99
144
  let(:result) { Easy::Api::Result.new }
100
- subject { result.to_xml }
145
+ subject(:parsed_xml) { Hash.from_xml(result.to_xml) }
101
146
 
102
147
  context "when result is unsuccessful" do
103
148
  let(:api_error) { Easy::Api::Error.new(:unauthorized) }
@@ -106,25 +151,51 @@ describe Easy::Api::Result do
106
151
  result.error = api_error
107
152
  end
108
153
 
109
- it "renders the object as " do
110
- expect(subject).to eql("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<response>\n <success>false</success>\n <error>\n <code>401</code>\n <message>Unauthorized request</message>\n </error>\n</response>\n")
154
+ it "includes the response.success value as false" do
155
+ expect(parsed_xml).to have_key('response')
156
+ expect(parsed_xml['response']).to have_key('success')
157
+ expect(parsed_xml['response']['success']).to eq('false')
111
158
  end
112
159
 
160
+ it "includes the response.error values" do
161
+ expect(parsed_xml).to eq({'response' => {'success' => 'false', 'error' => {'code' => '401', "message"=>"Unauthorized request"}}})
162
+ end
113
163
  end
114
164
 
115
165
  context "when result is successful" do
116
-
117
166
  before do
118
167
  result.success = true
119
168
  result.customer = "Bob Loblaw"
120
169
  end
121
170
 
122
171
  it "renders the object as " do
123
- expect(subject).to eql("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<response>\n <customer>Bob Loblaw</customer>\n <success>true</success>\n</response>\n")
172
+ expect(parsed_xml).to eql({'response' => {'customer' => 'Bob Loblaw', 'success' => 'true'}})
173
+ end
174
+ end
175
+
176
+ context "with some raw XML attributes" do
177
+ before do
178
+ result.success = true
179
+ result.rating = 'SUPER DUPER'
180
+ result.raw.customer = "<name>Tristan</name><age>17</age><height>2.04</height>"
124
181
  end
125
182
 
183
+ it 'should render the result including the RAW attributes' do
184
+ expect(parsed_xml).to eq({'response' => {'success' => 'true', 'rating' => 'SUPER DUPER', 'customer' => {'name' => 'Tristan', 'age' => '17', 'height' => '2.04'}}})
185
+ end
126
186
  end
127
187
 
188
+ context 'with some nested attributes that match the root element name' do
189
+ before do
190
+ result.success = true
191
+ result.response = 'Funny'
192
+ result.raw.customer = "<name>Charles</name>"
193
+ end
194
+
195
+ it 'should render the result including the RAW attributes' do
196
+ expect(parsed_xml).to eq({'response' => {'success' => 'true', 'response' => 'Funny', 'customer' => {'name' => 'Charles'}}})
197
+ end
198
+ end
128
199
  end
129
200
 
130
201
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easy-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shevaun Coker
@@ -10,120 +10,134 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-08-28 00:00:00.000000000 Z
13
+ date: 2015-12-20 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activemodel
17
17
  requirement: !ruby/object:Gem::Requirement
18
18
  requirements:
19
- - - '>='
19
+ - - ">="
20
20
  - !ruby/object:Gem::Version
21
21
  version: 3.0.0
22
22
  type: :development
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
- - - '>='
26
+ - - ">="
27
27
  - !ruby/object:Gem::Version
28
28
  version: 3.0.0
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: actionpack
31
31
  requirement: !ruby/object:Gem::Requirement
32
32
  requirements:
33
- - - '>='
33
+ - - ">="
34
34
  - !ruby/object:Gem::Version
35
35
  version: 3.0.0
36
36
  type: :development
37
37
  prerelease: false
38
38
  version_requirements: !ruby/object:Gem::Requirement
39
39
  requirements:
40
- - - '>='
40
+ - - ">="
41
41
  - !ruby/object:Gem::Version
42
42
  version: 3.0.0
43
43
  - !ruby/object:Gem::Dependency
44
44
  name: activesupport
45
45
  requirement: !ruby/object:Gem::Requirement
46
46
  requirements:
47
- - - '>='
47
+ - - ">="
48
48
  - !ruby/object:Gem::Version
49
49
  version: 3.0.0
50
50
  type: :development
51
51
  prerelease: false
52
52
  version_requirements: !ruby/object:Gem::Requirement
53
53
  requirements:
54
- - - '>='
54
+ - - ">="
55
55
  - !ruby/object:Gem::Version
56
56
  version: 3.0.0
57
57
  - !ruby/object:Gem::Dependency
58
58
  name: multi_json
59
59
  requirement: !ruby/object:Gem::Requirement
60
60
  requirements:
61
- - - ~>
61
+ - - "~>"
62
62
  - !ruby/object:Gem::Version
63
63
  version: '1.0'
64
64
  type: :development
65
65
  prerelease: false
66
66
  version_requirements: !ruby/object:Gem::Requirement
67
67
  requirements:
68
- - - ~>
68
+ - - "~>"
69
69
  - !ruby/object:Gem::Version
70
70
  version: '1.0'
71
71
  - !ruby/object:Gem::Dependency
72
72
  name: bundler
73
73
  requirement: !ruby/object:Gem::Requirement
74
74
  requirements:
75
- - - '>='
75
+ - - ">="
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
78
  type: :development
79
79
  prerelease: false
80
80
  version_requirements: !ruby/object:Gem::Requirement
81
81
  requirements:
82
- - - '>='
82
+ - - ">="
83
83
  - !ruby/object:Gem::Version
84
84
  version: '0'
85
85
  - !ruby/object:Gem::Dependency
86
86
  name: pry
87
87
  requirement: !ruby/object:Gem::Requirement
88
88
  requirements:
89
- - - '>='
89
+ - - ">="
90
90
  - !ruby/object:Gem::Version
91
91
  version: '0'
92
92
  type: :development
93
93
  prerelease: false
94
94
  version_requirements: !ruby/object:Gem::Requirement
95
95
  requirements:
96
- - - '>='
96
+ - - ">="
97
97
  - !ruby/object:Gem::Version
98
98
  version: '0'
99
99
  - !ruby/object:Gem::Dependency
100
100
  name: rspec
101
101
  requirement: !ruby/object:Gem::Requirement
102
102
  requirements:
103
- - - '>='
103
+ - - ">="
104
104
  - !ruby/object:Gem::Version
105
105
  version: '2.14'
106
106
  type: :development
107
107
  prerelease: false
108
108
  version_requirements: !ruby/object:Gem::Requirement
109
109
  requirements:
110
- - - '>='
110
+ - - ">="
111
111
  - !ruby/object:Gem::Version
112
112
  version: '2.14'
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: rspec-rails
115
115
  requirement: !ruby/object:Gem::Requirement
116
116
  requirements:
117
- - - '>='
117
+ - - ">="
118
118
  - !ruby/object:Gem::Version
119
119
  version: '0'
120
120
  type: :development
121
121
  prerelease: false
122
122
  version_requirements: !ruby/object:Gem::Requirement
123
123
  requirements:
124
- - - '>='
124
+ - - ">="
125
125
  - !ruby/object:Gem::Version
126
126
  version: '0'
127
+ - !ruby/object:Gem::Dependency
128
+ name: guard-rspec
129
+ requirement: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - "~>"
132
+ - !ruby/object:Gem::Version
133
+ version: '4.6'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - "~>"
139
+ - !ruby/object:Gem::Version
140
+ version: '4.6'
127
141
  description: Enables consistent responses for API calls
128
142
  email:
129
143
  - shevaun.coker@abletech.co.nz
@@ -133,10 +147,11 @@ executables: []
133
147
  extensions: []
134
148
  extra_rdoc_files: []
135
149
  files:
136
- - .gitignore
137
- - .travis.yml
150
+ - ".gitignore"
151
+ - ".travis.yml"
138
152
  - CHANGELOG.md
139
153
  - Gemfile
154
+ - Guardfile
140
155
  - LICENSE
141
156
  - README.md
142
157
  - Rakefile
@@ -165,17 +180,17 @@ require_paths:
165
180
  - lib
166
181
  required_ruby_version: !ruby/object:Gem::Requirement
167
182
  requirements:
168
- - - '>='
183
+ - - ">="
169
184
  - !ruby/object:Gem::Version
170
185
  version: '0'
171
186
  required_rubygems_version: !ruby/object:Gem::Requirement
172
187
  requirements:
173
- - - '>='
188
+ - - ">="
174
189
  - !ruby/object:Gem::Version
175
190
  version: '0'
176
191
  requirements: []
177
192
  rubyforge_project:
178
- rubygems_version: 2.2.2
193
+ rubygems_version: 2.4.5.1
179
194
  signing_key:
180
195
  specification_version: 4
181
196
  summary: Facilitates standard success and error behaviour in API responses