easy-api 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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