purple-client 0.1.7.3 → 0.1.7.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '08cd363a5b6e96500dde9beaa81ac46fdb282d6e6225d8ca19d4ba917c0b6f4f'
4
- data.tar.gz: 3eb93db2b0b359bc7b455ce6282bcc02d1d50991fbd8578a0527388b785fd9e8
3
+ metadata.gz: b5222522b4a3c4376e2a10f9ea7e4deece8f209d4f3fe4ac22dc9e12fe4445c7
4
+ data.tar.gz: e29a6b0c293f9dec1b84d322a46f8a00219c44890138e05b3ec507ae186eefb6
5
5
  SHA512:
6
- metadata.gz: 2653930ab7bcb2855c8ff142d401ffb8b1c676f0ca579f66fb7a780f8cb45760afff1f7f60fbabe7573091c4a877e6e5ea4d8d31d26c9dafd41a8c4d2b953095
7
- data.tar.gz: f2aacc6f3e1d6ca9b6661c5ad08be55f29b12061e1b037d30aca40ef7bb397ebb2b6ef88e6df772e66abf8bb7b61d6247d7d1980b35009d9f759d3bbd48504b5
6
+ metadata.gz: d9b273ed8a541e201b06221cb26696b9c6035bdbf06ae3d71dd37fad084b9e04a9a4b4af107284e32b98bf4076ee9ee26d67a41b34e83060b20530b2baf67ae3
7
+ data.tar.gz: 2c02a529e6df950dac3b480a0d736e3de51d822e5de6307ba9e6e8d675c8fe59623449475c664bc62300e2eb13e79e05cbd2d85bd2505eee9301f66d84239629
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Purple::Client
1
+ # Purple Client
2
2
 
3
3
  Purple::Client is a small DSL that helps you describe HTTP APIs. You define a domain, paths, and response structures, and the library generates handy methods for interacting with your service.
4
4
 
@@ -59,6 +59,36 @@ end
59
59
  JobsClient.job(123)
60
60
  ```
61
61
 
62
+ ### Simple POST request
63
+
64
+ ```ruby
65
+ class Amocrm::Client < Purple::Client
66
+ domain 'https://www.amocrm.ru'
67
+
68
+ path :oauth2 do
69
+ path :access_token, method: :post do
70
+ root_method :access_token
71
+
72
+ params do |client_id:, client_secret:, redirect_uri:, code:, grant_type: :authorization_code|
73
+ { client_id:, client_secret:, redirect_uri:, code:, grant_type: }
74
+ end
75
+
76
+ response :ok do
77
+ body(
78
+ token_type: String,
79
+ expires_in: Integer,
80
+ server_time: Integer,
81
+ access_token: String,
82
+ refresh_token: String
83
+ )
84
+ end
85
+
86
+ response :bad_request
87
+ end
88
+ end
89
+ end
90
+ ```
91
+
62
92
  ### Using authorization
63
93
 
64
94
  ```ruby
@@ -121,6 +151,36 @@ end
121
151
  PostsClient.user_posts(user_id: 7)
122
152
  ```
123
153
 
154
+ ### Paths nested under parameters
155
+
156
+ When a path segment is marked with `is_param: true`, any paths nested
157
+ inside it will not have a `root_method` generated. Instead of calling a
158
+ root method, you need to chain the segment methods manually.
159
+
160
+ ```ruby
161
+ class BrowserClient < Purple::Client
162
+ domain 'https://api.example.com'
163
+
164
+ path :browser do
165
+ path :id, is_param: true do
166
+ path :web, method: :post do
167
+ response :ok do
168
+ end
169
+
170
+ response :bad_request do
171
+ body do |res|
172
+ puts res
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
179
+
180
+ # root_method :web will not work here
181
+ BrowserClient.browser.id('123').web
182
+ ```
183
+
124
184
  ### Callbacks with additional arguments
125
185
 
126
186
  ```ruby
@@ -197,6 +257,30 @@ end
197
257
  CalendarClient.schedule
198
258
  ```
199
259
 
260
+ ### Allow blank fields
261
+
262
+ Some APIs return keys that are present but contain `null` or empty string values.
263
+ You can mark those fields with `allow_blank` so blank values do not raise
264
+ validation errors.
265
+
266
+ ```ruby
267
+ class ProfilesClient < Purple::Client
268
+ domain 'https://api.example.com'
269
+
270
+ path :profile do
271
+ response :ok do
272
+ body(
273
+ middle_name: { type: String, allow_blank: true },
274
+ )
275
+ end
276
+ root_method :profile
277
+ end
278
+ end
279
+
280
+ # The `middle_name` attribute may be blank or omitted in the response
281
+ ProfilesClient.profile
282
+ ```
283
+
200
284
  ### Array responses
201
285
 
202
286
  When an endpoint returns an array of objects, you can use `:array_of` to
@@ -226,6 +310,43 @@ end
226
310
  MerchantsClient.merchants
227
311
  ```
228
312
 
313
+ ### Response body processing
314
+
315
+ After the body structure is validated, you can supply a block to `body`
316
+ to transform or handle the parsed response. This is useful for mapping
317
+ error payloads to simpler return values or for normalizing data.
318
+
319
+ ```ruby
320
+ class MessagesClient < Purple::Client
321
+ domain 'https://api.example.com'
322
+
323
+ path :messages do
324
+ response :unprocessable_entity do
325
+ structure = {
326
+ status: Integer,
327
+ type: String,
328
+ title: String,
329
+ detail: String
330
+ }
331
+
332
+ body(**structure) do |res|
333
+ case res.type
334
+ when 'errors/invalid_recipient'
335
+ :not_found
336
+ else
337
+ res
338
+ end
339
+ end
340
+ end
341
+ root_method :send_message
342
+ end
343
+ end
344
+
345
+ # Returns :not_found when the recipient is invalid, otherwise returns the
346
+ # parsed response body.
347
+ MessagesClient.send_message
348
+ ```
349
+
229
350
  ## Development
230
351
 
231
352
  After checking out the repo, run `bin/setup` to install dependencies. Then run
data/lib/purple/path.rb CHANGED
@@ -27,7 +27,7 @@ module Purple
27
27
  @param_value = args.first
28
28
  end
29
29
 
30
- def method_missing(method_name, *args, &)
30
+ def method_missing(method_name, *args, **kw_args, &)
31
31
  if children.any? { |child| child.name == method_name }
32
32
  child = children.find { |child| child.name == method_name }
33
33
 
@@ -38,7 +38,7 @@ module Purple
38
38
  if child.children.any?
39
39
  child
40
40
  else
41
- callback_arguments = additional_callback_arguments.map do |arg|
41
+ callback_arguments = client.additional_callback_arguments.map do |arg|
42
42
  kw_args.delete(arg)
43
43
  end
44
44
 
@@ -12,6 +12,7 @@ class Purple::Response
12
12
  CODES = {
13
13
  ok: 200,
14
14
  created: 201,
15
+ accepted: 202,
15
16
  bad_request: 400,
16
17
  unauthorized: 401,
17
18
  unprocessable_entity: 422,
@@ -82,6 +82,10 @@ class Purple::Responses::Body
82
82
  end
83
83
  elsif value.is_a?(Array)
84
84
  object[key].each do |item|
85
+ if value[0].is_a?(Symbol)
86
+ raise "Body structure definition error in key '#{key}' of structure #{substructure}."
87
+ end
88
+
85
89
  check_structure!(item, value[0])
86
90
  end
87
91
  else
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Purple
4
- VERSION = "0.1.7.3"
4
+ VERSION = "0.1.7.5"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: purple-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7.3
4
+ version: 0.1.7.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pavel Kalashnikov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-08-12 00:00:00.000000000 Z
11
+ date: 2025-08-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-initializer