her 0.1.6 → 0.1.7
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.
- data/README.md +17 -12
- data/lib/her.rb +3 -2
- data/lib/her/api.rb +25 -30
- data/lib/her/middleware.rb +5 -0
- data/lib/her/middleware/default_parse_json.rb +18 -0
- data/lib/her/model/http.rb +1 -2
- data/lib/her/version.rb +1 -1
- data/spec/api_spec.rb +48 -22
- metadata +5 -3
data/README.md
CHANGED
@@ -86,25 +86,27 @@ By default, Her handles JSON data. It expects the data to be formatted in a cert
|
|
86
86
|
}
|
87
87
|
```
|
88
88
|
|
89
|
-
However, you can define your own parsing method,
|
89
|
+
However, you can define your own parsing method, using a Faraday response middleware. The middleware is expected to return a hash with three keys: `data`, `errors` and `metadata`. The following code enables parsing JSON data and treating this data as first-level properties:
|
90
90
|
|
91
91
|
```ruby
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
:
|
98
|
-
|
99
|
-
|
100
|
-
|
92
|
+
class MyCustomParser < Faraday::Response::Middleware
|
93
|
+
def on_complete(env)
|
94
|
+
json = JSON.parse(env[:body], :symbolize_names => true)
|
95
|
+
errors = json.delete(:errors) || []
|
96
|
+
metadata = json.delete(:metadata) || []
|
97
|
+
env[:body] = {
|
98
|
+
:data => json,
|
99
|
+
:errors => errors,
|
100
|
+
:metadata => metadata,
|
101
|
+
}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
Her::API.setup :base_uri => "https://api.example.com", :middleware => [MyCustomParser] + Her::API.default_middleware
|
101
105
|
end
|
102
106
|
|
103
107
|
# User.find(1) will now expect "https://api.example.com/users/1" to return something like '{ "id": 1, "name": "Tobias Fünke" }'
|
104
108
|
```
|
105
109
|
|
106
|
-
This feature is not stable and might change in the future, probably by using a middleware through [Faraday](https://github.com/technoweenie/faraday).
|
107
|
-
|
108
110
|
## Relationships
|
109
111
|
|
110
112
|
You can define `has_many`, `has_one` and `belongs_to` relationships in your models. The relationship data is handled in two different ways. When parsing a resource from JSON data, if there’s a relationship data included, it will be used to create new Ruby objects.
|
@@ -179,6 +181,9 @@ class User
|
|
179
181
|
self.internal_id = 42 # Will be passed in the HTTP request
|
180
182
|
end
|
181
183
|
end
|
184
|
+
|
185
|
+
@user = User.create(:fullname => "Tobias Fünke")
|
186
|
+
# POST /users&fullname=Tobias+Fünke&internal_id=42
|
182
187
|
```
|
183
188
|
|
184
189
|
In the future, adding hooks to all models will be possible, as well as defining and triggering your own hooks (eg. for your custom requests).
|
data/lib/her.rb
CHANGED
data/lib/her/api.rb
CHANGED
@@ -7,7 +7,7 @@ module Her
|
|
7
7
|
# $my_api.setup :base_uri => "https://api.example.com"
|
8
8
|
class API
|
9
9
|
# @private
|
10
|
-
attr_reader :base_uri, :
|
10
|
+
attr_reader :base_uri, :middleware
|
11
11
|
|
12
12
|
# Setup a default API connection
|
13
13
|
def self.setup(attrs={}) # {{{
|
@@ -20,20 +20,32 @@ module Her
|
|
20
20
|
defined?(@@default_api) ? @@default_api : nil
|
21
21
|
end # }}}
|
22
22
|
|
23
|
+
# @private
|
24
|
+
def self.default_middleware # {{{
|
25
|
+
[Faraday::Request::UrlEncoded, Faraday::Adapter::NetHttp]
|
26
|
+
end # }}}
|
27
|
+
|
23
28
|
# Setup the API connection
|
29
|
+
#
|
30
|
+
# @example
|
31
|
+
# module MyAPI
|
32
|
+
# class ParseResponse
|
33
|
+
# def on_complete(env)
|
34
|
+
# json = JSON.parse(env[:body], :symbolize_names => true)
|
35
|
+
# {
|
36
|
+
# :data => json,
|
37
|
+
# :errors => json[:errors] || [],
|
38
|
+
# :metadata => json[:metadata] || {},
|
39
|
+
# }
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
# Her::API.setup :base_url => "https://api.example.com", :middleware => [MyAPI::ParseResponse, Faraday::Request::UrlEncoded, Faraday::Adapter::NetHttp]
|
24
44
|
def setup(attrs={}) # {{{
|
25
45
|
@base_uri = attrs[:base_uri]
|
26
|
-
@
|
27
|
-
json = JSON.parse(response.body, :symbolize_names => true)
|
28
|
-
{
|
29
|
-
:data => json[:data],
|
30
|
-
:errors => json[:errors],
|
31
|
-
:metadata => json[:metadata],
|
32
|
-
}
|
33
|
-
end
|
46
|
+
middleware = @middleware = attrs[:middleware] || [Her::Middleware::DefaultParseJSON] + Her::API.default_middleware
|
34
47
|
@connection = Faraday.new(:url => @base_uri) do |builder|
|
35
|
-
builder.
|
36
|
-
builder.adapter :net_http
|
48
|
+
middleware.each { |m| builder.use(m) }
|
37
49
|
end
|
38
50
|
end # }}}
|
39
51
|
|
@@ -42,25 +54,12 @@ module Her
|
|
42
54
|
# and a metadata Hash.
|
43
55
|
#
|
44
56
|
# @example
|
45
|
-
# $my_api.parse_with do |response|
|
46
|
-
# json = JSON.parse(response.body)
|
47
|
-
# { :resource => json[:data], :errors => json[:errors], :metadata => json[:metdata] }
|
48
|
-
# end
|
49
|
-
def parse_with(&block) # {{{
|
50
|
-
@custom_parsing_block = true
|
51
|
-
@parse_with = block
|
52
|
-
end # }}}
|
53
|
-
|
54
|
-
# Return whether a custom parsing block has been defined
|
55
|
-
def custom_parsing_block? # {{{
|
56
|
-
@custom_parsing_block
|
57
|
-
end # }}}
|
58
57
|
|
59
58
|
# Make an HTTP request to the API
|
60
59
|
def request(attrs={}) # {{{
|
61
60
|
method = attrs.delete(:_method)
|
62
61
|
path = attrs.delete(:_path)
|
63
|
-
@connection.send method do |request|
|
62
|
+
response = @connection.send method do |request|
|
64
63
|
if method == :get
|
65
64
|
# For GET requests, treat additional parameters as querystring data
|
66
65
|
request.url path, attrs
|
@@ -70,11 +69,7 @@ module Her
|
|
70
69
|
request.body = attrs
|
71
70
|
end
|
72
71
|
end
|
73
|
-
|
74
|
-
|
75
|
-
# Parse the HTTP response
|
76
|
-
def parse(response) # {{{
|
77
|
-
@parse_with.call(response)
|
72
|
+
response.env[:body]
|
78
73
|
end # }}}
|
79
74
|
end
|
80
75
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Her
|
2
|
+
module Middleware
|
3
|
+
class DefaultParseJSON < Faraday::Response::Middleware
|
4
|
+
def parse(body)
|
5
|
+
json = JSON.parse(body, :symbolize_names => true)
|
6
|
+
return {
|
7
|
+
:data => json[:data],
|
8
|
+
:errors => json[:errors],
|
9
|
+
:metadata => json[:metadata],
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def on_complete(env)
|
14
|
+
env[:body] = parse env[:body]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/her/model/http.rb
CHANGED
@@ -34,8 +34,7 @@ module Her
|
|
34
34
|
# Main request wrapper around Her::API. Used to make custom request to the API.
|
35
35
|
# @private
|
36
36
|
def request(attrs={}, &block) # {{{
|
37
|
-
|
38
|
-
yield @her_api.parse(response)
|
37
|
+
yield @her_api.request(attrs)
|
39
38
|
end # }}}
|
40
39
|
|
41
40
|
# Make a GET request and return the parsed JSON response (not mapped to objects)
|
data/lib/her/version.rb
CHANGED
data/spec/api_spec.rb
CHANGED
@@ -17,43 +17,69 @@ describe Her::API do
|
|
17
17
|
@api.base_uri.should == "https://api.example.com"
|
18
18
|
end # }}}
|
19
19
|
|
20
|
-
it "sets
|
20
|
+
it "sets middleware" do # {{{
|
21
|
+
class Foo < Faraday::Response::Middleware; end;
|
22
|
+
class Bar < Faraday::Response::Middleware; end;
|
23
|
+
|
21
24
|
@api = Her::API.new
|
22
|
-
@api.setup :base_uri => "https://api.example.com"
|
23
|
-
@api.
|
24
|
-
response.body
|
25
|
-
end
|
26
|
-
@api.custom_parsing_block?.should be_true
|
25
|
+
@api.setup :base_uri => "https://api.example.com", :middleware => [Foo, Bar]
|
26
|
+
@api.middleware.should == [Foo, Bar]
|
27
27
|
end # }}}
|
28
28
|
end
|
29
29
|
|
30
30
|
describe "#request" do
|
31
|
-
|
32
|
-
@api = Her::API.new
|
33
|
-
@api.setup :base_uri => "https://api.example.com"
|
31
|
+
it "makes HTTP requests" do # {{{
|
34
32
|
FakeWeb.register_uri(:get, "https://api.example.com/foo", :body => "Foo, it is.")
|
35
|
-
end # }}}
|
36
33
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
class Foo < Faraday::Response::Middleware
|
35
|
+
def on_complete(env)
|
36
|
+
env[:body] = { :data => env[:body] }
|
37
|
+
end
|
38
|
+
end
|
42
39
|
|
43
|
-
describe "#parse" do
|
44
|
-
before do # {{{
|
45
40
|
@api = Her::API.new
|
46
|
-
@api.setup :base_uri => "https://api.example.com"
|
47
|
-
|
41
|
+
@api.setup :base_uri => "https://api.example.com", :middleware => []
|
42
|
+
@api.request(:_method => :get, :_path => "/foo") do |parsed_data|
|
43
|
+
parsed_data[:data] == "Foo, it is."
|
44
|
+
end
|
48
45
|
end # }}}
|
49
46
|
|
50
|
-
it "parses a request" do # {{{
|
51
|
-
|
52
|
-
|
47
|
+
it "parses a request with the default parser" do # {{{
|
48
|
+
FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :data => { :id => 1, :name => "George Michael Bluth" }, :errors => ["This is a single error"], :metadata => { :page => 1, :per_page => 10 }}.to_json)
|
49
|
+
|
50
|
+
@api = Her::API.new
|
51
|
+
@api.setup :base_uri => "https://api.example.com"
|
52
|
+
@api.request(:_method => :get, :_path => "users/1") do |parsed_data|
|
53
|
+
parsed_data[:data].should == { :id => 1, :name => "George Michael Bluth" }
|
53
54
|
parsed_data[:errors].should == ["This is a single error"]
|
54
55
|
parsed_data[:metadata].should == { :page => 1, :per_page => 10 }
|
55
56
|
end
|
56
57
|
end # }}}
|
58
|
+
|
59
|
+
it "parses a request with a custom parser" do # {{{
|
60
|
+
FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :id => 1, :name => "George Michael Bluth" }.to_json)
|
61
|
+
|
62
|
+
class CustomParser < Faraday::Response::Middleware
|
63
|
+
def on_complete(env)
|
64
|
+
json = JSON.parse(env[:body], :symbolize_names => true)
|
65
|
+
errors = json.delete(:errors) || []
|
66
|
+
metadata = json.delete(:metadata) || {}
|
67
|
+
env[:body] = {
|
68
|
+
:data => json,
|
69
|
+
:errors => errors,
|
70
|
+
:metadata => metadata,
|
71
|
+
}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
@api = Her::API.new
|
76
|
+
@api.setup :base_uri => "https://api.example.com", :middleware => [CustomParser] + Her::API.default_middleware
|
77
|
+
@api.request(:_method => :get, :_path => "users/1") do |parsed_data|
|
78
|
+
parsed_data[:data].should == { :id => 1, :name => "George Michael Bluth" }
|
79
|
+
parsed_data[:errors].should == []
|
80
|
+
parsed_data[:metadata].should == {}
|
81
|
+
end
|
82
|
+
end # }}}
|
57
83
|
end
|
58
84
|
end
|
59
85
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: her
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -171,6 +171,8 @@ files:
|
|
171
171
|
- her.gemspec
|
172
172
|
- lib/her.rb
|
173
173
|
- lib/her/api.rb
|
174
|
+
- lib/her/middleware.rb
|
175
|
+
- lib/her/middleware/default_parse_json.rb
|
174
176
|
- lib/her/model.rb
|
175
177
|
- lib/her/model/base.rb
|
176
178
|
- lib/her/model/hooks.rb
|
@@ -198,7 +200,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
198
200
|
version: '0'
|
199
201
|
segments:
|
200
202
|
- 0
|
201
|
-
hash:
|
203
|
+
hash: -2767021996149695300
|
202
204
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
203
205
|
none: false
|
204
206
|
requirements:
|
@@ -207,7 +209,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
207
209
|
version: '0'
|
208
210
|
segments:
|
209
211
|
- 0
|
210
|
-
hash:
|
212
|
+
hash: -2767021996149695300
|
211
213
|
requirements: []
|
212
214
|
rubyforge_project:
|
213
215
|
rubygems_version: 1.8.18
|