bootic_client 0.0.2 → 0.0.3

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: c3577184c13b3c030b8e7bce4bd7e560856564de
4
- data.tar.gz: 06ceb2c371d1f60bdb4f246821397789401aa4d9
3
+ metadata.gz: 727d4868928f07359322ccc49dfed3d20edfae0a
4
+ data.tar.gz: 7626595ffbef58af0b052b6a74c3dc220b3e32ca
5
5
  SHA512:
6
- metadata.gz: 5de054c0e2b96d5782e857f962991d27118552d23bd973d581a890d3074a46edb5869c36ff179a142f7b261dadb9d905ab7dae38d7b729d3b600b4bca8bbbff6
7
- data.tar.gz: 43a6af6c0fef9c9bb91481b29a94fe788578778ff4a3d76942a56c7ce32992b3d5d7a7a5c05bc63fe0813c6b7837b17871da49f4764ebb55f069eef86663e09d
6
+ metadata.gz: 56d7d5c1c16e19f61f5d9e59de8b494f3ba20f8510c7eaba5d21a1d2aeab1a97eaf125c80c5923b524dd422c6f75904ddb5f20fd3c98f4d52765dce18e2e1071
7
+ data.tar.gz: 8fb91e3fcfbed8a09bf3903e3952f9078554b381d657eec9d92b08b1e955741a40c5e3c46b2f67dada5f3d0cac45feb1a337d2536c25a762606835a27af2ef94
data/README.md CHANGED
@@ -88,6 +88,48 @@ client = BooticClient.client(:client_credentials, scope: 'admin', access_token:
88
88
  end
89
89
  ```
90
90
 
91
+ ## Non GET links
92
+
93
+ Most resource links lead to `GET` resources, but some will expect `POST`, `PUT`, `DELETE` or others.
94
+
95
+ The Bootic API encodes this information in its link metadata so the client will do the right thing. The following example creates a new product on your first shop:
96
+
97
+ ```ruby
98
+ bootic = BooticClient.client(:client_credentials)
99
+
100
+ root = bootic.root
101
+
102
+ shop = root.shops.first
103
+
104
+ if shop.can?(:create_product)
105
+ product = shop.create_product(
106
+ title: 'A shiny new product',
107
+ price: 122332,
108
+ status: "visible",
109
+ collecton_names: ["Featured products", "Homepage"],
110
+ variants: [
111
+ {
112
+ title: 'First variant',
113
+ sku: 'F23332-X',
114
+ available_if_no_stock: 1,
115
+ stock: 12
116
+ }
117
+ ]
118
+ )
119
+
120
+ puts product.rels[:web].href # => 'http://acme.bootic.net/products/a-shiny-new-product'
121
+ end
122
+ ```
123
+
124
+ ## Relation docs
125
+
126
+ All resource link relations include a "docs" URL so you can learn more about that particular resource.
127
+
128
+ ```ruby
129
+ shop = root.shops.first
130
+ puts shop.rels[:create_product] # => 'https://developers.bootic.net/rels/create_product'
131
+ ```
132
+
91
133
  ## Cache storage
92
134
 
93
135
  `BooticClient` honours HTTP caching headers included in API responses (such as `ETag` and `Last-Modified`).
@@ -9,6 +9,7 @@ module BooticClient
9
9
  class Client
10
10
 
11
11
  USER_AGENT = "[BooticClient v#{VERSION}] Ruby-#{RUBY_VERSION} - #{RUBY_PLATFORM}".freeze
12
+ JSON_MIME = 'application/json'.freeze
12
13
 
13
14
  attr_reader :options, :api_root
14
15
 
@@ -28,19 +29,30 @@ module BooticClient
28
29
  wrapper_class.new get(href, query).body, self
29
30
  end
30
31
 
31
- def get(href, query = {})
32
- validate_request!
32
+ def post_and_wrap(href, wrapper_class, payload = {})
33
+ wrapper_class.new post(href, payload).body, self
34
+ end
33
35
 
34
- resp = conn.get do |req|
35
- req.url href
36
- req.params.update(query)
37
- req.headers['Authorization'] = "Bearer #{options[:access_token]}"
38
- req.headers['User-Agent'] = USER_AGENT
36
+ def get(href, query = {})
37
+ validated! do
38
+ conn.get do |req|
39
+ req.url href
40
+ req.headers.update request_headers
41
+ req.params.update(query)
42
+ end
39
43
  end
44
+ end
40
45
 
41
- raise_if_invalid! resp
42
-
43
- resp
46
+ def post(href, payload = {})
47
+ validated! do
48
+ conn.post do |req|
49
+ req.url href
50
+ req.headers.update request_headers
51
+ req.headers['Accept'] = JSON_MIME
52
+ req.headers['Content-Type'] = JSON_MIME
53
+ req.body = JSON.dump(payload)
54
+ end
55
+ end
44
56
  end
45
57
 
46
58
  protected
@@ -58,6 +70,20 @@ module BooticClient
58
70
  end
59
71
  end
60
72
 
73
+ def request_headers
74
+ {
75
+ 'Authorization' => "Bearer #{options[:access_token]}",
76
+ 'User-Agent' => USER_AGENT
77
+ }
78
+ end
79
+
80
+ def validated!(&block)
81
+ validate_request!
82
+ resp = yield
83
+ raise_if_invalid! resp
84
+ resp
85
+ end
86
+
61
87
  def validate_request!
62
88
  raise NoAccessTokenError, "Missing access token" unless options[:access_token]
63
89
  end
@@ -23,6 +23,10 @@ module BooticClient
23
23
  has_property?(prop_name) || has_entity?(prop_name) || has_rel?(prop_name)
24
24
  end
25
25
 
26
+ def can?(rel_name)
27
+ has_rel? rel_name
28
+ end
29
+
26
30
  def inspect
27
31
  %(#<#{self.class.name} props: [#{properties.keys.join(', ')}] rels: [#{rels.keys.join(', ')}] entities: [#{entities.keys.join(', ')}]>)
28
32
  end
@@ -55,7 +59,7 @@ module BooticClient
55
59
  elsif has_entity?(name)
56
60
  entities[name]
57
61
  elsif has_rel?(name)
58
- rels[name].get(*args)
62
+ rels[name].run(*args)
59
63
  else
60
64
  super
61
65
  end
@@ -5,6 +5,8 @@ module BooticClient
5
5
 
6
6
  class Relation
7
7
 
8
+ GET = 'get'.freeze
9
+
8
10
  def initialize(attrs, client, wrapper_class = Entity)
9
11
  @attrs, @client, @wrapper_class = attrs, client, wrapper_class
10
12
  end
@@ -37,6 +39,14 @@ module BooticClient
37
39
  attrs['docs']
38
40
  end
39
41
 
42
+ def transport_method
43
+ @transport_method ||= attrs['method'] || GET
44
+ end
45
+
46
+ def run(opts = {})
47
+ self.send(transport_method, opts)
48
+ end
49
+
40
50
  def get(opts = {})
41
51
  if templated?
42
52
  client.get_and_wrap uri.expand(opts), wrapper_class
@@ -45,6 +55,10 @@ module BooticClient
45
55
  end
46
56
  end
47
57
 
58
+ def post(opts = {})
59
+ client.post_and_wrap href, wrapper_class, opts
60
+ end
61
+
48
62
  def self.expand(href, opts = {})
49
63
  URITemplate.new(href).expand(opts)
50
64
  end
@@ -1,3 +1,3 @@
1
1
  module BooticClient
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
data/spec/client_spec.rb CHANGED
@@ -135,5 +135,20 @@ describe BooticClient::Client do
135
135
  end
136
136
  end
137
137
 
138
+ describe '#post_and_wrap' do
139
+ before do
140
+ stub_request(:post, root_url)
141
+ .with(body: JSON.dump({foo: 'bar'}), headers: {'Accept' => 'application/json', 'Content-Type' => 'application/json'})
142
+ .to_return(status: 200, body: JSON.dump(root_data), headers: response_headers)
143
+ end
144
+
145
+ it 'wraps JSON response in entity' do
146
+ wrapper = double('Wrapper Class')
147
+ entity = double('Entity')
148
+ expect(wrapper).to receive(:new).with(root_data, client).and_return entity
149
+ expect(client.post_and_wrap(root_url, wrapper, foo: 'bar')).to eql(entity)
150
+ end
151
+ end
152
+
138
153
  end
139
154
  end
data/spec/entity_spec.rb CHANGED
@@ -111,6 +111,11 @@ describe BooticClient::Entity do
111
111
  expect(entity.has?(:next)).to eql(true)
112
112
  end
113
113
 
114
+ it 'responds to #can? for link relations' do
115
+ expect(entity.can?(:next)).to eql(true)
116
+ expect(entity.can?(:foo)).to eql(false)
117
+ end
118
+
114
119
  it 'builds relation objects' do
115
120
  expect(entity.rels[:next]).to be_kind_of(BooticClient::Relation)
116
121
  expect(entity.rels[:next].href).to eql('/foo?page=2')
@@ -13,42 +13,53 @@ describe BooticClient::Relation do
13
13
  end
14
14
  end
15
15
 
16
- describe '#get' do
16
+ describe '#run' do
17
17
  let(:entity) { BooticClient::Entity.new({'title' => 'Foobar'}, client) }
18
18
 
19
- it 'fetches data and returns entity' do
20
- client.stub(:get_and_wrap).with('/foo/bars', BooticClient::Entity, {}).and_return entity
21
- expect(relation.get).to eql(entity)
22
- end
19
+ describe 'running GET by default' do
20
+ it 'fetches data and returns entity' do
21
+ client.stub(:get_and_wrap).with('/foo/bars', BooticClient::Entity, {}).and_return entity
22
+ expect(relation.run).to eql(entity)
23
+ end
23
24
 
24
- context 'without URI templates' do
25
- let(:relation) { BooticClient::Relation.new({'href' => '/foos/bar', 'type' => 'application/json', 'title' => 'A relation'}, client) }
25
+ context 'without URI templates' do
26
+ let(:relation) { BooticClient::Relation.new({'href' => '/foos/bar', 'type' => 'application/json', 'title' => 'A relation'}, client) }
26
27
 
27
- it 'is not templated' do
28
- expect(relation.templated?).to eql(false)
29
- end
28
+ it 'is not templated' do
29
+ expect(relation.templated?).to eql(false)
30
+ end
30
31
 
31
- it 'passes query string to client' do
32
- expect(client).to receive(:get_and_wrap).with('/foos/bar', BooticClient::Entity, id: 2, q: 'test', page: 2).and_return entity
33
- expect(relation.get(id: 2, q: 'test', page: 2)).to eql(entity)
32
+ it 'passes query string to client' do
33
+ expect(client).to receive(:get_and_wrap).with('/foos/bar', BooticClient::Entity, id: 2, q: 'test', page: 2).and_return entity
34
+ expect(relation.run(id: 2, q: 'test', page: 2)).to eql(entity)
35
+ end
34
36
  end
35
- end
36
37
 
37
- context 'with URI templates' do
38
- let(:relation) { BooticClient::Relation.new({'href' => '/foos/{id}{?q,page}', 'type' => 'application/json', 'title' => 'A relation', 'templated' => true}, client) }
38
+ context 'with URI templates' do
39
+ let(:relation) { BooticClient::Relation.new({'href' => '/foos/{id}{?q,page}', 'type' => 'application/json', 'title' => 'A relation', 'templated' => true}, client) }
39
40
 
40
- it 'is templated' do
41
- expect(relation.templated?).to eql(true)
42
- end
41
+ it 'is templated' do
42
+ expect(relation.templated?).to eql(true)
43
+ end
44
+
45
+ it 'works with defaults' do
46
+ expect(client).to receive(:get_and_wrap).with('/foos/', BooticClient::Entity).and_return entity
47
+ expect(relation.run).to eql(entity)
48
+ end
43
49
 
44
- it 'works with defaults' do
45
- expect(client).to receive(:get_and_wrap).with('/foos/', BooticClient::Entity).and_return entity
46
- expect(relation.get).to eql(entity)
50
+ it 'interpolates tokens' do
51
+ expect(client).to receive(:get_and_wrap).with('/foos/2?q=test&page=2', BooticClient::Entity).and_return entity
52
+ expect(relation.run(id: 2, q: 'test', page: 2)).to eql(entity)
53
+ end
47
54
  end
55
+ end
56
+
57
+ describe 'POST' do
58
+ let(:relation) { BooticClient::Relation.new({'href' => '/foo/bars', 'type' => 'application/json', 'name' => 'self', 'method' => 'post'}, client) }
48
59
 
49
- it 'interpolates tokens' do
50
- expect(client).to receive(:get_and_wrap).with('/foos/2?q=test&page=2', BooticClient::Entity).and_return entity
51
- expect(relation.get(id: 2, q: 'test', page: 2)).to eql(entity)
60
+ it 'POSTS data and returns resulting entity' do
61
+ client.stub(:post_and_wrap).with('/foo/bars', BooticClient::Entity, {}).and_return entity
62
+ expect(relation.run).to eql(entity)
52
63
  end
53
64
  end
54
65
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bootic_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ismael Celis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-17 00:00:00.000000000 Z
11
+ date: 2014-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday