Skip to content
Newer
Older
100644 230 lines (168 sloc) 6.59 KB
871ef96 @remiprev Add README
authored Apr 8, 2012
1 # Her
2
3 [![Build Status](https://secure.travis-ci.org/remiprev/her.png)](http://travis-ci.org/remiprev/her)
4
a6e9967 @remiprev Update README with more examples
authored Apr 9, 2012
5 Her is an ORM (Object Relational Mapper) that maps REST resources to Ruby objects. It is designed to build applications that are powered by a RESTful API and no database.
871ef96 @remiprev Add README
authored Apr 9, 2012
6
7 ## Installation
8
9 In your Gemfile, add:
10
60f209e @remiprev Update README
authored Apr 8, 2012
11 ```ruby
12 gem "her"
13 ```
871ef96 @remiprev Add README
authored Apr 9, 2012
14
6878101 @remiprev Update documentation with new API code
authored Apr 8, 2012
15 That’s it!
16
871ef96 @remiprev Add README
authored Apr 9, 2012
17 ## Usage
18
6878101 @remiprev Update documentation with new API code
authored Apr 9, 2012
19 First, you have to define which API your models will be bound to. For example, with Rails, you would create a new `config/initializers/her.rb` file with this line:
871ef96 @remiprev Add README
authored Apr 9, 2012
20
21 ```ruby
cdeb59f @remiprev Add Multiple APIs section in README
authored Apr 9, 2012
22 # config/initializers/her.rb
6878101 @remiprev Update documentation with new API code
authored Apr 9, 2012
23 Her::API.setup :base_uri => "https://api.example.com"
871ef96 @remiprev Add README
authored Apr 9, 2012
24 ```
25
6878101 @remiprev Update documentation with new API code
authored Apr 9, 2012
26 And then to add the ORM behavior to a class, you just have to include `Her::Model` in it:
871ef96 @remiprev Add README
authored Apr 9, 2012
27
28 ```ruby
29 class User
30 include Her::Model
31 end
32 ```
33
34 After that, using Her is very similar to many ActiveModel-like ORMs:
35
36 ```ruby
a6e9967 @remiprev Update README with more examples
authored Apr 9, 2012
37 User.all
cdeb59f @remiprev Add Multiple APIs section in README
authored Apr 9, 2012
38 # GET https://api.example.com/users and return an array of User objects
a6e9967 @remiprev Update README with more examples
authored Apr 9, 2012
39
40 User.find(1)
cdeb59f @remiprev Add Multiple APIs section in README
authored Apr 9, 2012
41 # GET https://api.example.com/users/1 and return a User object
a6e9967 @remiprev Update README with more examples
authored Apr 9, 2012
42
43 @user = User.create(:fullname => "Tobias Fünke")
bc5779a @remiprev Fix typo
authored Apr 9, 2012
44 # POST "https://api.example.com/users" with the data and return a User object
a6e9967 @remiprev Update README with more examples
authored Apr 9, 2012
45
46 @user = User.new(:fullname => "Tobias Fünke")
47 @user.occupation = "actor"
48 @user.save
cdeb59f @remiprev Add Multiple APIs section in README
authored Apr 9, 2012
49 # POST https://api.example.com/users with the data and return a User object
a6e9967 @remiprev Update README with more examples
authored Apr 9, 2012
50
51 @user = User.find(1)
52 @user.fullname = "Lindsay Fünke"
53 @user.save
cdeb59f @remiprev Add Multiple APIs section in README
authored Apr 9, 2012
54 # PUT https://api.example.com/users/1 with the data and return+update the User object
871ef96 @remiprev Add README
authored Apr 9, 2012
55 ```
60f209e @remiprev Update README
authored Apr 9, 2012
56
ab31348 @remiprev Add Parsing data section in README
authored Apr 9, 2012
57 ## Parsing data
58
59 By default, Her handles JSON data. It expects the data to be formatted in a certain structure. The default is this:
60
8f55b37 @remiprev Fix typo in README
authored Apr 9, 2012
61 ```javascript
ab31348 @remiprev Add Parsing data section in README
authored Apr 9, 2012
62 // The response of GET /users/1
63 {
64 "data" : {
65 "id" : 1,
66 "name" : "Tobias Fünke"
67 }
68 }
69
70 // The response of GET /users
71 {
72 "data" : [
73 {
74 "id" : 1,
75 "name" : "Tobias Fünke"
76 },
77 {
78 "id" : 2,
79 "name" : "Lindsay Fünke"
80 }
8f55b37 @remiprev Fix typo in README
authored Apr 9, 2012
81 ],
ab31348 @remiprev Add Parsing data section in README
authored Apr 9, 2012
82 "metadata" : {
83 "page" : 1,
84 "per_page" : 10
85 }
86 }
87 ```
88
8a5bee6 @remiprev Fix a few typos
authored Apr 9, 2012
89 However, you can define your own parsing method, with `Her::API.parse_with`. The `parse_with` method takes a block which will be executed each time data from an HTTP response needs to be parsed. The block 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:
ab31348 @remiprev Add Parsing data section in README
authored Apr 9, 2012
90
91 ```ruby
92 Her::API.setup :base_uri => "https://api.example.com"
93 Her::API.parse_with |response|
94 json = JSON.parse(response.body, :symbolize_names => true)
95 errors = json.delete(:errors)
96 {
97 :data => json,
98 :errors => errors || [],
99 :metadata => {}
100 }
101 end
8a5bee6 @remiprev Fix a few typos
authored Apr 9, 2012
102
103 # User.find(1) will now expect "https://api.example.com/users/1" to return something like '{ "id": 1, "name": "Tobias Fünke" }'
ab31348 @remiprev Add Parsing data section in README
authored Apr 9, 2012
104 ```
105
8a5bee6 @remiprev Fix a few typos
authored Apr 9, 2012
106 This feature is not stable and might change in the future, probably by using a middleware through [Faraday](https://github.com/technoweenie/faraday).
ab31348 @remiprev Add Parsing data section in README
authored Apr 9, 2012
107
6878101 @remiprev Update documentation with new API code
authored Apr 9, 2012
108 ## Relationships
109
d997547 Updated readme for has_one relationship
jfcixmedia authored Apr 10, 2012
110 You can define `has_many` and `has_one` 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.
313c487 @remiprev Add better documentation for relationships
authored Apr 9, 2012
111
112 If no relationship data was included when parsing a resource, calling a method with the same name as the relationship will fetch the data (providing there’s an HTTP request available for it).
113
114 For example, with this setup:
115
6878101 @remiprev Update documentation with new API code
authored Apr 9, 2012
116 ```ruby
117 class User
118 include Her::Model
119 has_many :comments
d997547 Updated readme for has_one relationship
jfcixmedia authored Apr 11, 2012
120 has_one :role
6878101 @remiprev Update documentation with new API code
authored Apr 9, 2012
121 end
122
123 class Comment
124 include Her::Model
125 end
d997547 Updated readme for has_one relationship
jfcixmedia authored Apr 11, 2012
126
127 class Role
128 include Her::Model
129 end
313c487 @remiprev Add better documentation for relationships
authored Apr 9, 2012
130 ```
131
dc37005 @remiprev Better english in README
authored Apr 9, 2012
132 If there’s relationship data in the resource, no extra HTTP request is made when calling the `#comments` method and an array of resources are returned:
6878101 @remiprev Update documentation with new API code
authored Apr 9, 2012
133
313c487 @remiprev Add better documentation for relationships
authored Apr 9, 2012
134 ```ruby
d997547 Updated readme for has_one relationship
jfcixmedia authored Apr 11, 2012
135 @user = User.find(1) # { :data => { :id => 1, :name => "George Michael Bluth", :comments => [{ :id => 1, :text => "Foo" }, { :id => 2, :text => "Bar" }], :role => { :id => 1, :name => "Admin" } }}
313c487 @remiprev Add better documentation for relationships
authored Apr 9, 2012
136 @user.comments # => [#<Comment id=1>, #<Comment id=2>] fetched directly from @user
d997547 Updated readme for has_one relationship
jfcixmedia authored Apr 11, 2012
137 @user.role # => #<Role id=1> fetched directly from @user
6878101 @remiprev Update documentation with new API code
authored Apr 9, 2012
138 ```
139
313c487 @remiprev Add better documentation for relationships
authored Apr 9, 2012
140 If there’s no relationship data in the resource, an extra HTTP request (to `GET /users/1/comments`) is made when calling the `#comments` method:
141
142 ```ruby
a6e9967 @remiprev Update README with more examples
authored Apr 9, 2012
143 @user = User.find(1) # { :data => { :id => 1, :name => "George Michael Bluth" }}
313c487 @remiprev Add better documentation for relationships
authored Apr 9, 2012
144 @user.comments # => [#<Comment id=1>, #<Comment id=2>] fetched from /users/1/comments
145 ```
146
d997547 Updated readme for has_one relationship
jfcixmedia authored Apr 11, 2012
147 For `has_one` relationship, an extra HTTP request (to `GET /users/1/role`) is made when calling the `#role` method:
148
149 ```ruby
150 @user = User.find(1) # { :data => { :id => 1, :name => "George Michael Bluth" }}
151 @user.role # => #<Role id=1> fetched from /users/1/role
152 ```
153
154 However, subsequent calls to `#comments` or `#role` will not trigger the extra HTTP request.
313c487 @remiprev Add better documentation for relationships
authored Apr 9, 2012
155
6878101 @remiprev Update documentation with new API code
authored Apr 9, 2012
156 ## Custom requests
157
a6e9967 @remiprev Update README with more examples
authored Apr 9, 2012
158 You can easily add custom methods for your models. You can either use `get_collection` (which maps the returned data to a collection of resources), `get_resource` (which maps the returned data to a single resource) or `get_raw` (which yields the parsed data return from the HTTP request). Other HTTP methods are supported (`post_raw`, `put_resource`, etc.)
6878101 @remiprev Update documentation with new API code
authored Apr 9, 2012
159
17d968c @remiprev Improve support for custom methods
authored Apr 9, 2012
160 ```ruby
161 class User
162 include Her::Model
163
164 def self.popular
165 get_collection("/users/popular")
166 end
6878101 @remiprev Update documentation with new API code
authored Apr 9, 2012
167
17d968c @remiprev Improve support for custom methods
authored Apr 9, 2012
168 def self.total
169 get_raw("/users/stats") do |parsed_data|
170 parsed_data[:data][:total_users]
171 end
172 end
173 end
174
175 User.popular # => [#<User id=1>, #<User id=2>]
176 User.total # => 42
177 ```
7f7392f @remiprev Improve README and add LICENSE
authored Apr 9, 2012
178
cdeb59f @remiprev Add Multiple APIs section in README
authored Apr 9, 2012
179 ## Multiple APIs
180
181 It is possible to use different APIs for different models. Instead of calling `Her::API.setup`, you can create instances of `Her::API`:
182
183 ```ruby
184 # config/initializers/her.rb
185 $my_api = Her::API.new
186 $my_api.setup :base_uri => "https://my_api.example.com"
187
188 $other_api = Her::API.new
189 $other_api.setup :base_uri => "https://other_api.example.com"
190 ```
191
192 You can then define which API a model will use:
193
194 ```ruby
195 class User
196 include Her::Model
197 uses_api $my_api
198 end
199
200 class Category
201 include Her::Model
202 uses_api $other_api
203 end
204
205 User.all
206 # GET https://my_api.example.com/users
207
208 Category.all
209 # GET https://other_api.example.com/categories
210 ```
211
7f7392f @remiprev Improve README and add LICENSE
authored Apr 9, 2012
212 ## Things to be done
213
214 * Deleting resources
88fe92f @remiprev Add note in README for middlware
authored Apr 9, 2012
215 * Support for Faraday middleware to handle caching, alternative formats, etc.
7f7392f @remiprev Improve README and add LICENSE
authored Apr 9, 2012
216 * Hooks before save, update, create, destroy, etc.
a6e9967 @remiprev Update README with more examples
authored Apr 9, 2012
217 * Better error handling
7f7392f @remiprev Improve README and add LICENSE
authored Apr 9, 2012
218 * Better introspection for debug
219 * Better documentation
220
221 ## Contributors
222
223 Feel free to contribute and submit issues/pull requests [on GitHub](https://github.com/remiprev/her/issues).
224
225 Take a look at the `spec` folder before you do, and make sure `bundle exec rake spec` passes after your modifications :)
226
227 ## License
228
e0f75c8 @remiprev Fix typo in README, d’uh.
authored Apr 9, 2012
229 Her is © 2012 [Rémi Prévost](http://exomel.com) and may be freely distributed under the [LITL license](https://github.com/remiprev/her/blob/master/LICENSE). See the `LICENSE` file.
Something went wrong with that request. Please try again.