Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 215 lines (157 sloc) 6.125 kb
871ef96 Rémi Prévost Add README
authored
1 # Her
2
3 [![Build Status](https://secure.travis-ci.org/remiprev/her.png)](http://travis-ci.org/remiprev/her)
4
a6e9967 Rémi Prévost Update README with more examples
authored
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 Rémi Prévost Add README
authored
6
7 ## Installation
8
9 In your Gemfile, add:
10
60f209e Rémi Prévost Update README
authored
11 ```ruby
12 gem "her"
13 ```
871ef96 Rémi Prévost Add README
authored
14
6878101 Rémi Prévost Update documentation with new API code
authored
15 That’s it!
16
871ef96 Rémi Prévost Add README
authored
17 ## Usage
18
6878101 Rémi Prévost Update documentation with new API code
authored
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 Rémi Prévost Add README
authored
20
21 ```ruby
cdeb59f Rémi Prévost Add Multiple APIs section in README
authored
22 # config/initializers/her.rb
6878101 Rémi Prévost Update documentation with new API code
authored
23 Her::API.setup :base_uri => "https://api.example.com"
871ef96 Rémi Prévost Add README
authored
24 ```
25
6878101 Rémi Prévost Update documentation with new API code
authored
26 And then to add the ORM behavior to a class, you just have to include `Her::Model` in it:
871ef96 Rémi Prévost Add README
authored
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 Rémi Prévost Update README with more examples
authored
37 User.all
cdeb59f Rémi Prévost Add Multiple APIs section in README
authored
38 # GET https://api.example.com/users and return an array of User objects
a6e9967 Rémi Prévost Update README with more examples
authored
39
40 User.find(1)
cdeb59f Rémi Prévost Add Multiple APIs section in README
authored
41 # GET https://api.example.com/users/1 and return a User object
a6e9967 Rémi Prévost Update README with more examples
authored
42
43 @user = User.create(:fullname => "Tobias Fünke")
bc5779a Rémi Prévost Fix typo
authored
44 # POST "https://api.example.com/users" with the data and return a User object
a6e9967 Rémi Prévost Update README with more examples
authored
45
46 @user = User.new(:fullname => "Tobias Fünke")
47 @user.occupation = "actor"
48 @user.save
cdeb59f Rémi Prévost Add Multiple APIs section in README
authored
49 # POST https://api.example.com/users with the data and return a User object
a6e9967 Rémi Prévost Update README with more examples
authored
50
51 @user = User.find(1)
52 @user.fullname = "Lindsay Fünke"
53 @user.save
cdeb59f Rémi Prévost Add Multiple APIs section in README
authored
54 # PUT https://api.example.com/users/1 with the data and return+update the User object
871ef96 Rémi Prévost Add README
authored
55 ```
60f209e Rémi Prévost Update README
authored
56
ab31348 Rémi Prévost Add Parsing data section in README
authored
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
61 ```json
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 }
81 ]
82 "metadata" : {
83 "page" : 1,
84 "per_page" : 10
85 }
86 }
87 ```
88
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.
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
102 ```
103
104 This feature is not stable and might change in the future, probably by using a middleware throught [Faraday](https://github.com/technoweenie/faraday).
105
6878101 Rémi Prévost Update documentation with new API code
authored
106 ## Relationships
107
313c487 Rémi Prévost Add better documentation for relationships
authored
108 You can define `has_many` 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.
109
110 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).
111
112 For example, with this setup:
113
6878101 Rémi Prévost Update documentation with new API code
authored
114 ```ruby
115 class User
116 include Her::Model
117 has_many :comments
118 end
119
120 class Comment
121 include Her::Model
122 end
313c487 Rémi Prévost Add better documentation for relationships
authored
123 ```
124
dc37005 Rémi Prévost Better english in README
authored
125 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 Rémi Prévost Update documentation with new API code
authored
126
313c487 Rémi Prévost Add better documentation for relationships
authored
127 ```ruby
a6e9967 Rémi Prévost Update README with more examples
authored
128 @user = User.find(1) # { :data => { :id => 1, :name => "George Michael Bluth", :comments => [{ :id => 1, :text => "Foo" }, { :id => 2, :text => "Bar" }] }}
313c487 Rémi Prévost Add better documentation for relationships
authored
129 @user.comments # => [#<Comment id=1>, #<Comment id=2>] fetched directly from @user
6878101 Rémi Prévost Update documentation with new API code
authored
130 ```
131
313c487 Rémi Prévost Add better documentation for relationships
authored
132 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:
133
134 ```ruby
a6e9967 Rémi Prévost Update README with more examples
authored
135 @user = User.find(1) # { :data => { :id => 1, :name => "George Michael Bluth" }}
313c487 Rémi Prévost Add better documentation for relationships
authored
136 @user.comments # => [#<Comment id=1>, #<Comment id=2>] fetched from /users/1/comments
137 ```
138
139 However, subsequent calls to `#comments` will not trigger the extra HTTP request.
140
6878101 Rémi Prévost Update documentation with new API code
authored
141 ## Custom requests
142
a6e9967 Rémi Prévost Update README with more examples
authored
143 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 Rémi Prévost Update documentation with new API code
authored
144
17d968c Rémi Prévost Improve support for custom methods
authored
145 ```ruby
146 class User
147 include Her::Model
148
149 def self.popular
150 get_collection("/users/popular")
151 end
6878101 Rémi Prévost Update documentation with new API code
authored
152
17d968c Rémi Prévost Improve support for custom methods
authored
153 def self.total
154 get_raw("/users/stats") do |parsed_data|
155 parsed_data[:data][:total_users]
156 end
157 end
158 end
159
160 User.popular # => [#<User id=1>, #<User id=2>]
161 User.total # => 42
162 ```
7f7392f Rémi Prévost Improve README and add LICENSE
authored
163
cdeb59f Rémi Prévost Add Multiple APIs section in README
authored
164 ## Multiple APIs
165
166 It is possible to use different APIs for different models. Instead of calling `Her::API.setup`, you can create instances of `Her::API`:
167
168 ```ruby
169 # config/initializers/her.rb
170 $my_api = Her::API.new
171 $my_api.setup :base_uri => "https://my_api.example.com"
172
173 $other_api = Her::API.new
174 $other_api.setup :base_uri => "https://other_api.example.com"
175 ```
176
177 You can then define which API a model will use:
178
179 ```ruby
180 class User
181 include Her::Model
182 uses_api $my_api
183 end
184
185 class Category
186 include Her::Model
187 uses_api $other_api
188 end
189
190 User.all
191 # GET https://my_api.example.com/users
192
193 Category.all
194 # GET https://other_api.example.com/categories
195 ```
196
7f7392f Rémi Prévost Improve README and add LICENSE
authored
197 ## Things to be done
198
199 * Deleting resources
200 * Support for Faraday middleware
201 * Hooks before save, update, create, destroy, etc.
a6e9967 Rémi Prévost Update README with more examples
authored
202 * Better error handling
7f7392f Rémi Prévost Improve README and add LICENSE
authored
203 * Better introspection for debug
204 * Better documentation
205
206 ## Contributors
207
208 Feel free to contribute and submit issues/pull requests [on GitHub](https://github.com/remiprev/her/issues).
209
210 Take a look at the `spec` folder before you do, and make sure `bundle exec rake spec` passes after your modifications :)
211
212 ## License
213
e0f75c8 Rémi Prévost Fix typo in README, d’uh.
authored
214 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.