uploadcare-api_struct 1.1.0

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.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +25 -0
  3. data/.gitignore +18 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +15 -0
  6. data/CHANGELOG.md +15 -0
  7. data/Gemfile +6 -0
  8. data/Gemfile.lock +123 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +211 -0
  11. data/Rakefile +6 -0
  12. data/api_struct.gemspec +36 -0
  13. data/api_struct.svg +1 -0
  14. data/bin/console +14 -0
  15. data/bin/setup +8 -0
  16. data/lib/api_struct/client.rb +88 -0
  17. data/lib/api_struct/collection.rb +19 -0
  18. data/lib/api_struct/concerns/underscore.rb +7 -0
  19. data/lib/api_struct/entity.rb +93 -0
  20. data/lib/api_struct/errors/client.rb +43 -0
  21. data/lib/api_struct/errors/entity.rb +7 -0
  22. data/lib/api_struct/extensions/api_client.rb +43 -0
  23. data/lib/api_struct/extensions/dry_monads.rb +22 -0
  24. data/lib/api_struct/settings.rb +7 -0
  25. data/lib/api_struct/version.rb +3 -0
  26. data/lib/api_struct.rb +20 -0
  27. data/spec/api_struct/client_spec.rb +156 -0
  28. data/spec/api_struct/entity_spec.rb +188 -0
  29. data/spec/fixtures/cassettes/posts/1.yml +73 -0
  30. data/spec/fixtures/cassettes/posts/index_success.yml +1335 -0
  31. data/spec/fixtures/cassettes/posts/show_failure.yml +67 -0
  32. data/spec/fixtures/cassettes/posts/show_failure_html.yml +67 -0
  33. data/spec/fixtures/cassettes/posts/show_success.yml +74 -0
  34. data/spec/fixtures/cassettes/posts/suffix.yml +73 -0
  35. data/spec/fixtures/cassettes/posts/update_success.yml +71 -0
  36. data/spec/fixtures/cassettes/todos.yml +143 -0
  37. data/spec/fixtures/cassettes/user_todos.yml +189 -0
  38. data/spec/fixtures/cassettes/users/1/posts/1.yml +797 -0
  39. data/spec/fixtures/cassettes/users/1/posts.yml +1049 -0
  40. data/spec/spec_helper.rb +26 -0
  41. data/spec/support/stub.rb +9 -0
  42. metadata +283 -0
@@ -0,0 +1,188 @@
1
+ describe ApiStruct::Entity do
2
+ extend Support::Stub
3
+
4
+ stub_api('https://jsonplaceholder.typicode.com')
5
+
6
+ # rubocop:disable Lint/ConstantDefinitionInBlock
7
+ class StubClient < ApiStruct::Client
8
+ stub_api 'posts'
9
+
10
+ def show(id)
11
+ get(id)
12
+ end
13
+
14
+ def index(params = {})
15
+ get(json: params)
16
+ end
17
+ end
18
+
19
+ class StubNestedEntity < ApiStruct::Entity
20
+ attr_entity :name
21
+ end
22
+
23
+ class StubEntity < ApiStruct::Entity
24
+ client_service StubClient
25
+ client_service StubClient, prefix: true
26
+ client_service StubClient, prefix: :custom
27
+ client_service StubClient, prefix: :only, only: :index
28
+ client_service StubClient, prefix: :except, except: :show
29
+
30
+ attr_entity :id, :title, :camel_case
31
+
32
+ has_entity :nested_entity, as: StubNestedEntity
33
+ has_entities :another_nested_entities, as: StubNestedEntity
34
+ end
35
+ # rubocop:enable Lint/ConstantDefinitionInBlock
36
+
37
+ let(:response) { { title: FFaker::Name.name, 'id' => rand(1..100), another_attributes: FFaker::Name.name } }
38
+ let(:nested_response) { { name: FFaker::Name.name } }
39
+
40
+ it '.new' do
41
+ entity = StubEntity.new(response)
42
+
43
+ expect(entity).to be_success
44
+ expect(entity.id).to eq(response['id'])
45
+ expect(entity.title).to eq(response[:title])
46
+ expect { entity.another_attributes }.to raise_error(NoMethodError)
47
+ end
48
+
49
+ it '.collection' do
50
+ entities = StubEntity.collection([response, response])
51
+
52
+ expect(entities.count).to eq(2)
53
+ expect(entities.success?).to eq(true)
54
+ expect(entities.failure?).to eq(false)
55
+ expect(entities.class).to eq(ApiStruct::Collection)
56
+ expect(entities.first.title).to eq(response[:title])
57
+ end
58
+
59
+ context 'Nested entity' do
60
+ it 'when response is valid' do
61
+ response[:nested_entity] = nested_response
62
+ entity = StubEntity.new(response)
63
+ nested_entity = entity.nested_entity
64
+
65
+ expect(nested_entity.class).to eq(StubNestedEntity)
66
+ expect(nested_entity.name).to eq(nested_response[:name])
67
+ end
68
+
69
+ it 'when response is invalid' do
70
+ response[:nested_entity] = [nested_response]
71
+ entity = StubEntity.new(response)
72
+
73
+ expect { entity.nested_entity }.to raise_error(ApiStruct::EntityError)
74
+ end
75
+ end
76
+
77
+ context 'Nested entities' do
78
+ it 'when response is valid' do
79
+ response[:another_nested_entities] = [nested_response]
80
+ entity = StubEntity.new(response)
81
+ nested_entity = entity.another_nested_entities.first
82
+
83
+ expect(nested_entity.class).to eq(StubNestedEntity)
84
+ expect(nested_entity.name).to eq(nested_response[:name])
85
+ end
86
+
87
+ it 'when response is invalid' do
88
+ response[:another_nested_entities] = nested_response
89
+ entity = StubEntity.new(response)
90
+
91
+ expect { entity.another_nested_entities }.to raise_error(ApiStruct::EntityError)
92
+ end
93
+ end
94
+
95
+ context 'From monad' do
96
+ it 'convert to entity', type: :webmock do
97
+ VCR.use_cassette('posts/show_success') do
98
+ entity = StubEntity.from_monad(StubClient.new.show(1))
99
+
100
+ expect(entity).to be_success
101
+ expect(entity.id).to eq(1)
102
+ expect(entity.title).not_to be_empty
103
+ end
104
+ end
105
+
106
+ it 'convert to collection of entities', type: :webmock do
107
+ VCR.use_cassette('posts/index_success') do
108
+ entities = StubEntity.from_monad(StubClient.new.index)
109
+
110
+ expect(entities.class).to eq(ApiStruct::Collection)
111
+ expect(entities.first.id).to eq(1)
112
+ end
113
+ end
114
+ end
115
+
116
+ context 'From client service' do
117
+ it 'convert to entity', type: :webmock do
118
+ VCR.use_cassette('posts/show_success') do
119
+ entity = StubEntity.show(1)
120
+
121
+ expect(entity).to be_success
122
+ expect(entity.id).to eq(1)
123
+ expect(entity.title).not_to be_empty
124
+ expect(entity.camel_case).not_to be_empty
125
+ end
126
+ end
127
+
128
+ it 'convert to collection of entities', type: :webmock do
129
+ VCR.use_cassette('posts/index_success') do
130
+ entities = StubEntity.index
131
+
132
+ expect(entities.class).to eq(ApiStruct::Collection)
133
+ expect(entities.first.id).to eq(1)
134
+ end
135
+ end
136
+ end
137
+
138
+ describe '.client_service' do
139
+ context 'prefix' do
140
+ context 'empty' do
141
+ it 'should register client as base' do
142
+ expect(StubEntity.clients[:base]).to eq StubClient
143
+ end
144
+
145
+ it 'should define client methods without prefix' do
146
+ expect(StubEntity).to be_respond_to(:show)
147
+ expect(StubEntity).to be_respond_to(:index)
148
+ end
149
+ end
150
+
151
+ context 'eq true' do
152
+ it 'should register client as stubclient' do
153
+ expect(StubEntity.clients[:stub_client]).to eq StubClient
154
+ end
155
+
156
+ it 'should define client methods' do
157
+ expect(StubEntity).to be_respond_to(:stub_client_show)
158
+ expect(StubEntity).to be_respond_to(:stub_client_index)
159
+ end
160
+ end
161
+
162
+ context 'eq string' do
163
+ it 'should register client as custom' do
164
+ expect(StubEntity.clients[:custom]).to eq StubClient
165
+ end
166
+
167
+ it 'should define client methods' do
168
+ expect(StubEntity).to be_respond_to(:custom_show)
169
+ expect(StubEntity).to be_respond_to(:custom_index)
170
+ end
171
+ end
172
+ end
173
+
174
+ context 'only' do
175
+ it 'should define methods from options[:only]' do
176
+ expect(StubEntity).to be_respond_to(:only_index)
177
+ expect(StubEntity).not_to be_respond_to(:only_show)
178
+ end
179
+ end
180
+
181
+ context 'except' do
182
+ it 'should define all methods except options[:except]' do
183
+ expect(StubEntity).to be_respond_to(:except_index)
184
+ expect(StubEntity).not_to be_respond_to(:except_show)
185
+ end
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,73 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://jsonplaceholder.typicode.com/posts/1
6
+ body:
7
+ encoding: UTF-8
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - application/json
12
+ Content-Type:
13
+ - application/json
14
+ Connection:
15
+ - close
16
+ Host:
17
+ - jsonplaceholder.typicode.com
18
+ User-Agent:
19
+ - http.rb/3.0.0
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: OK
24
+ headers:
25
+ Date:
26
+ - Tue, 06 Mar 2018 08:02:15 GMT
27
+ Content-Type:
28
+ - application/json; charset=utf-8
29
+ Content-Length:
30
+ - '292'
31
+ Connection:
32
+ - close
33
+ Set-Cookie:
34
+ - __cfduid=db9bcdebf92e32fd92ce9630387d2e0761520323335; expires=Wed, 06-Mar-19
35
+ 08:02:15 GMT; path=/; domain=.typicode.com; HttpOnly
36
+ X-Powered-By:
37
+ - Express
38
+ Vary:
39
+ - Origin, Accept-Encoding
40
+ Access-Control-Allow-Credentials:
41
+ - 'true'
42
+ Cache-Control:
43
+ - public, max-age=14400
44
+ Pragma:
45
+ - no-cache
46
+ Expires:
47
+ - Tue, 06 Mar 2018 12:02:15 GMT
48
+ X-Content-Type-Options:
49
+ - nosniff
50
+ Etag:
51
+ - W/"124-yiKdLzqO5gfBrJFrcdJ8Yq0LGnU"
52
+ Via:
53
+ - 1.1 vegur
54
+ Cf-Cache-Status:
55
+ - HIT
56
+ Expect-Ct:
57
+ - max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
58
+ Server:
59
+ - cloudflare
60
+ Cf-Ray:
61
+ - 3f734c8d68fb8d7d-DME
62
+ body:
63
+ encoding: UTF-8
64
+ string: |-
65
+ {
66
+ "userId": 1,
67
+ "id": 1,
68
+ "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
69
+ "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
70
+ }
71
+ http_version:
72
+ recorded_at: Tue, 06 Mar 2018 08:09:11 GMT
73
+ recorded_with: VCR 3.0.3