pylon-api 0.2.0 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -31
- data/lib/pylon/client.rb +141 -86
- data/lib/pylon/models/account.rb +8 -0
- data/lib/pylon/models/article.rb +8 -0
- data/lib/pylon/models/attachment.rb +8 -0
- data/lib/pylon/models/base.rb +40 -0
- data/lib/pylon/models/collection.rb +39 -0
- data/lib/pylon/models/contact.rb +8 -0
- data/lib/pylon/models/issue.rb +8 -0
- data/lib/pylon/models/tag.rb +8 -0
- data/lib/pylon/models/team.rb +8 -0
- data/lib/pylon/models/ticket_form.rb +8 -0
- data/lib/pylon/models/user.rb +8 -0
- data/lib/pylon/version.rb +2 -2
- data/lib/pylon.rb +11 -0
- metadata +33 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d98b4389f4182e2f3d62261c2a60d9f4a325c18a5376c09668cc17e1594219c
|
4
|
+
data.tar.gz: ea1c690a74e4e8d2890098211d58909ae551af8deecaf757d3463e5de37f3cdc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3a1dcd703454b3efc5818292f01a00366a50ddfa5f06d6dbbdbfc865907b907b05ea35d0ca591e0eb93d5ffbec26e4ad90b85e47379aa029f61346b766e81f1
|
7
|
+
data.tar.gz: aa703a9d4f20da2243ce49b31627548afd719835a3a591fab2ffafd5480ab84cbce02b3c88a54b25979a8138641b584c9e32054ae673f548ca4936daa2531e53
|
data/CHANGELOG.md
CHANGED
@@ -1,40 +1,25 @@
|
|
1
1
|
# Changelog
|
2
|
-
All notable changes to this project will be documented in this file.
|
3
2
|
|
4
|
-
|
5
|
-
|
3
|
+
## [1.0.0] - 2024-03-21
|
4
|
+
|
5
|
+
### Changed
|
6
|
+
- Downgraded Faraday dependency from 2.12.2 to 1.10.4 for better compatibility with existing applications
|
7
|
+
- Updated Faraday multipart and retry dependencies to match Faraday 1.x compatibility
|
6
8
|
|
7
9
|
## [0.2.0] - 2024-03-21
|
8
10
|
|
9
11
|
### Added
|
10
|
-
- Added
|
12
|
+
- Added support for file uploads via multipart/form-data
|
13
|
+
- Added retry mechanism for failed requests
|
14
|
+
- Added comprehensive error handling and logging
|
11
15
|
|
12
|
-
|
16
|
+
### Changed
|
17
|
+
- Improved request/response logging
|
18
|
+
- Enhanced error messages and documentation
|
13
19
|
|
14
|
-
|
15
|
-
- Initial release of the Pylon API Ruby client
|
16
|
-
- Comprehensive client implementation with support for all major API endpoints:
|
17
|
-
- Accounts management
|
18
|
-
- Attachments handling
|
19
|
-
- Contacts management
|
20
|
-
- Custom fields
|
21
|
-
- Issues tracking
|
22
|
-
- Knowledge base articles
|
23
|
-
- Tags management
|
24
|
-
- Teams management
|
25
|
-
- Ticket forms
|
26
|
-
- User roles
|
27
|
-
- Users management
|
28
|
-
- Robust error handling with specific error classes:
|
29
|
-
- `Pylon::AuthenticationError`
|
30
|
-
- `Pylon::ResourceNotFoundError`
|
31
|
-
- `Pylon::ValidationError`
|
32
|
-
- `Pylon::ApiError`
|
33
|
-
- Pagination support for list endpoints
|
34
|
-
- Debug mode for request/response logging
|
35
|
-
- Comprehensive test suite with RSpec
|
36
|
-
- YARD documentation for all methods
|
37
|
-
- MIT License
|
20
|
+
## [0.1.0] - 2024-03-20
|
38
21
|
|
39
|
-
|
40
|
-
|
22
|
+
### Added
|
23
|
+
- Initial release
|
24
|
+
- Basic API client functionality
|
25
|
+
- Support for core API endpoints
|
data/lib/pylon/client.rb
CHANGED
@@ -6,6 +6,7 @@ module Pylon
|
|
6
6
|
# @example
|
7
7
|
# client = Pylon::Client.new(api_key: 'your_api_key')
|
8
8
|
# issues = client.list_issues(start_time: '2024-03-01T00:00:00Z', end_time: '2024-03-31T23:59:59Z')
|
9
|
+
# issues.each { |issue| puts issue.title }
|
9
10
|
class Client
|
10
11
|
# Base URL for the Pylon API
|
11
12
|
BASE_URL = "https://api.usepylon.com"
|
@@ -28,76 +29,78 @@ module Pylon
|
|
28
29
|
#
|
29
30
|
# @param page [Integer] Page number for pagination
|
30
31
|
# @param per_page [Integer] Number of items per page
|
31
|
-
# @return [
|
32
|
+
# @return [Models::Collection<Models::Account>] Collection of account objects
|
32
33
|
def list_accounts(page: 1, per_page: 20)
|
33
|
-
get("/accounts", query: { page: page, per_page: per_page }
|
34
|
+
get("/accounts", query: { page: page, per_page: per_page },
|
35
|
+
model_class: Models::Account, collection: true)
|
34
36
|
end
|
35
37
|
|
36
38
|
# Get details for a specific account
|
37
39
|
#
|
38
40
|
# @param account_id [String] The ID of the account to retrieve
|
39
|
-
# @return [
|
41
|
+
# @return [Models::Account] Account object
|
40
42
|
def get_account(account_id)
|
41
|
-
get("/accounts/#{account_id}")
|
43
|
+
get("/accounts/#{account_id}", model_class: Models::Account)
|
42
44
|
end
|
43
45
|
|
44
46
|
# Create a new attachment
|
45
47
|
#
|
46
48
|
# @param file [String] The file content to upload
|
47
|
-
# @return [
|
49
|
+
# @return [Models::Attachment] Created attachment object
|
48
50
|
def create_attachment(file)
|
49
|
-
post("/attachments", body: { file: file })
|
51
|
+
post("/attachments", body: { file: file }, model_class: Models::Attachment)
|
50
52
|
end
|
51
53
|
|
52
54
|
# Get details for a specific attachment
|
53
55
|
#
|
54
56
|
# @param attachment_id [String] The ID of the attachment to retrieve
|
55
|
-
# @return [
|
57
|
+
# @return [Models::Attachment] Attachment object
|
56
58
|
def get_attachment(attachment_id)
|
57
|
-
get("/attachments/#{attachment_id}")
|
59
|
+
get("/attachments/#{attachment_id}", model_class: Models::Attachment)
|
58
60
|
end
|
59
61
|
|
60
62
|
# List all contacts with pagination
|
61
63
|
#
|
62
64
|
# @param page [Integer] Page number for pagination
|
63
65
|
# @param per_page [Integer] Number of items per page
|
64
|
-
# @return [
|
66
|
+
# @return [Models::Collection<Models::Contact>] Collection of contact objects
|
65
67
|
def list_contacts(page: 1, per_page: 20)
|
66
|
-
get("/contacts", query: { page: page, per_page: per_page }
|
68
|
+
get("/contacts", query: { page: page, per_page: per_page },
|
69
|
+
model_class: Models::Contact, collection: true)
|
67
70
|
end
|
68
71
|
|
69
72
|
# Create a new contact
|
70
73
|
#
|
71
74
|
# @param params [Hash] Contact parameters
|
72
|
-
# @return [
|
75
|
+
# @return [Models::Contact] Created contact object
|
73
76
|
def create_contact(params)
|
74
|
-
post("/contacts", body: params)
|
77
|
+
post("/contacts", body: params, model_class: Models::Contact)
|
75
78
|
end
|
76
79
|
|
77
80
|
# Get details for a specific contact
|
78
81
|
#
|
79
82
|
# @param contact_id [String] The ID of the contact to retrieve
|
80
|
-
# @return [
|
83
|
+
# @return [Models::Contact] Contact object
|
81
84
|
def get_contact(contact_id)
|
82
|
-
get("/contacts/#{contact_id}")
|
85
|
+
get("/contacts/#{contact_id}", model_class: Models::Contact)
|
83
86
|
end
|
84
87
|
|
85
88
|
# Update an existing contact
|
86
89
|
#
|
87
90
|
# @param contact_id [String] The ID of the contact to update
|
88
91
|
# @param params [Hash] Updated contact parameters
|
89
|
-
# @return [
|
92
|
+
# @return [Models::Contact] Updated contact object
|
90
93
|
def update_contact(contact_id, params)
|
91
|
-
patch("/contacts/#{contact_id}", body: params)
|
94
|
+
patch("/contacts/#{contact_id}", body: params, model_class: Models::Contact)
|
92
95
|
end
|
93
96
|
|
94
97
|
# List all custom fields with pagination
|
95
98
|
#
|
96
99
|
# @param page [Integer] Page number for pagination
|
97
100
|
# @param per_page [Integer] Number of items per page
|
98
|
-
# @return [
|
101
|
+
# @return [Models::Collection] Collection of custom fields
|
99
102
|
def list_custom_fields(page: 1, per_page: 20)
|
100
|
-
get("/custom_fields", query: { page: page, per_page: per_page })
|
103
|
+
get("/custom_fields", query: { page: page, per_page: per_page }, collection: true)
|
101
104
|
end
|
102
105
|
|
103
106
|
# Create a new custom field
|
@@ -115,7 +118,7 @@ module Pylon
|
|
115
118
|
# @param page [Integer] Page number for pagination
|
116
119
|
# @param per_page [Integer] Number of items per page
|
117
120
|
# @param filters [Hash] Additional filters to apply
|
118
|
-
# @return [
|
121
|
+
# @return [Models::Collection<Models::Issue>] Collection of issue objects
|
119
122
|
# @raise [ArgumentError] If start_time or end_time is missing
|
120
123
|
def list_issues(start_time:, end_time:, page: 1, per_page: 20, **filters)
|
121
124
|
raise ArgumentError, "start_time is required" unless start_time
|
@@ -126,135 +129,140 @@ module Pylon
|
|
126
129
|
end_time: end_time,
|
127
130
|
page: page,
|
128
131
|
per_page: per_page
|
129
|
-
))
|
132
|
+
), model_class: Models::Issue, collection: true)
|
130
133
|
end
|
131
134
|
|
132
135
|
# Create a new issue
|
133
136
|
#
|
134
137
|
# @param params [Hash] Issue parameters
|
135
|
-
# @return [
|
138
|
+
# @return [Models::Issue] Created issue object
|
136
139
|
def create_issue(params)
|
137
|
-
post("/issues", body: params)
|
140
|
+
post("/issues", body: params, model_class: Models::Issue)
|
138
141
|
end
|
139
142
|
|
140
143
|
# Get details for a specific issue
|
141
144
|
#
|
142
145
|
# @param issue_id [String] The ID of the issue to retrieve
|
143
|
-
# @return [
|
146
|
+
# @return [Models::Issue] Issue object
|
144
147
|
def get_issue(issue_id)
|
145
|
-
get("/issues/#{issue_id}")
|
148
|
+
get("/issues/#{issue_id}", model_class: Models::Issue)
|
146
149
|
end
|
147
150
|
|
148
151
|
# Update an existing issue
|
149
152
|
#
|
150
153
|
# @param issue_id [String] The ID of the issue to update
|
151
154
|
# @param params [Hash] Updated issue parameters
|
152
|
-
# @return [
|
155
|
+
# @return [Models::Issue] Updated issue object
|
153
156
|
def update_issue(issue_id, params)
|
154
|
-
patch("/issues/#{issue_id}", body: params)
|
157
|
+
patch("/issues/#{issue_id}", body: params, model_class: Models::Issue)
|
155
158
|
end
|
156
159
|
|
157
160
|
# Snooze an issue until a specified time
|
158
161
|
#
|
159
162
|
# @param issue_id [String] The ID or number of the issue to snooze
|
160
163
|
# @param snooze_until [String] The date and time to snooze the issue until (RFC3339 format)
|
161
|
-
# @return [
|
164
|
+
# @return [Models::Issue] Updated issue object
|
162
165
|
def snooze_issue(issue_id, snooze_until:)
|
163
|
-
post("/issues/#{issue_id}/snooze", body: { snooze_until: snooze_until }
|
166
|
+
post("/issues/#{issue_id}/snooze", body: { snooze_until: snooze_until },
|
167
|
+
model_class: Models::Issue)
|
164
168
|
end
|
165
169
|
|
166
170
|
# List all knowledge base articles with pagination
|
167
171
|
#
|
168
172
|
# @param page [Integer] Page number for pagination
|
169
173
|
# @param per_page [Integer] Number of items per page
|
170
|
-
# @return [
|
174
|
+
# @return [Models::Collection<Models::Article>] Collection of article objects
|
171
175
|
def list_articles(page: 1, per_page: 20)
|
172
|
-
get("/knowledge_base/articles", query: { page: page, per_page: per_page }
|
176
|
+
get("/knowledge_base/articles", query: { page: page, per_page: per_page },
|
177
|
+
model_class: Models::Article, collection: true)
|
173
178
|
end
|
174
179
|
|
175
180
|
# Get details for a specific article
|
176
181
|
#
|
177
182
|
# @param article_id [String] The ID of the article to retrieve
|
178
|
-
# @return [
|
183
|
+
# @return [Models::Article] Article object
|
179
184
|
def get_article(article_id)
|
180
|
-
get("/knowledge_base/articles/#{article_id}")
|
185
|
+
get("/knowledge_base/articles/#{article_id}", model_class: Models::Article)
|
181
186
|
end
|
182
187
|
|
183
188
|
# Get details for the current user
|
184
189
|
#
|
185
|
-
# @return [
|
190
|
+
# @return [Models::User] Current user object
|
186
191
|
def get_current_user
|
187
|
-
get("/me")
|
192
|
+
get("/me", model_class: Models::User)
|
188
193
|
end
|
189
194
|
|
190
195
|
# List all tags with pagination
|
191
196
|
#
|
192
197
|
# @param page [Integer] Page number for pagination
|
193
198
|
# @param per_page [Integer] Number of items per page
|
194
|
-
# @return [
|
199
|
+
# @return [Models::Collection<Models::Tag>] Collection of tag objects
|
195
200
|
def list_tags(page: 1, per_page: 20)
|
196
|
-
get("/tags", query: { page: page, per_page: per_page }
|
201
|
+
get("/tags", query: { page: page, per_page: per_page },
|
202
|
+
model_class: Models::Tag, collection: true)
|
197
203
|
end
|
198
204
|
|
199
205
|
# Create a new tag
|
200
206
|
#
|
201
207
|
# @param name [String] The name of the tag
|
202
208
|
# @param color [String] Optional hex color code for the tag
|
203
|
-
# @return [
|
209
|
+
# @return [Models::Tag] Created tag object
|
204
210
|
def create_tag(name:, color: nil)
|
205
|
-
post("/tags", body: { name: name, color: color }.compact)
|
211
|
+
post("/tags", body: { name: name, color: color }.compact, model_class: Models::Tag)
|
206
212
|
end
|
207
213
|
|
208
214
|
# List all teams with pagination
|
209
215
|
#
|
210
216
|
# @param page [Integer] Page number for pagination
|
211
217
|
# @param per_page [Integer] Number of items per page
|
212
|
-
# @return [
|
218
|
+
# @return [Models::Collection<Models::Team>] Collection of team objects
|
213
219
|
def list_teams(page: 1, per_page: 20)
|
214
|
-
get("/teams", query: { page: page, per_page: per_page }
|
220
|
+
get("/teams", query: { page: page, per_page: per_page },
|
221
|
+
model_class: Models::Team, collection: true)
|
215
222
|
end
|
216
223
|
|
217
224
|
# Create a new team
|
218
225
|
#
|
219
226
|
# @param params [Hash] Team parameters
|
220
|
-
# @return [
|
227
|
+
# @return [Models::Team] Created team object
|
221
228
|
def create_team(params)
|
222
|
-
post("/teams", body: params)
|
229
|
+
post("/teams", body: params, model_class: Models::Team)
|
223
230
|
end
|
224
231
|
|
225
232
|
# Get details for a specific team
|
226
233
|
#
|
227
234
|
# @param team_id [String] The ID of the team to retrieve
|
228
|
-
# @return [
|
235
|
+
# @return [Models::Team] Team object
|
229
236
|
def get_team(team_id)
|
230
|
-
get("/teams/#{team_id}")
|
237
|
+
get("/teams/#{team_id}", model_class: Models::Team)
|
231
238
|
end
|
232
239
|
|
233
240
|
# List all ticket forms with pagination
|
234
241
|
#
|
235
242
|
# @param page [Integer] Page number for pagination
|
236
243
|
# @param per_page [Integer] Number of items per page
|
237
|
-
# @return [
|
244
|
+
# @return [Models::Collection<Models::TicketForm>] Collection of ticket form objects
|
238
245
|
def list_ticket_forms(page: 1, per_page: 20)
|
239
|
-
get("/ticket-forms", query: { page: page, per_page: per_page }
|
246
|
+
get("/ticket-forms", query: { page: page, per_page: per_page },
|
247
|
+
model_class: Models::TicketForm, collection: true)
|
240
248
|
end
|
241
249
|
|
242
250
|
# Create a new ticket form
|
243
251
|
#
|
244
252
|
# @param name [String] The name of the form
|
245
253
|
# @param fields [Array<Hash>] Array of form field definitions
|
246
|
-
# @return [
|
254
|
+
# @return [Models::TicketForm] Created ticket form object
|
247
255
|
def create_ticket_form(name:, fields: [])
|
248
|
-
post("/ticket-forms", body: { name: name, fields: fields })
|
256
|
+
post("/ticket-forms", body: { name: name, fields: fields }, model_class: Models::TicketForm)
|
249
257
|
end
|
250
258
|
|
251
259
|
# List all user roles with pagination
|
252
260
|
#
|
253
261
|
# @param page [Integer] Page number for pagination
|
254
262
|
# @param per_page [Integer] Number of items per page
|
255
|
-
# @return [
|
263
|
+
# @return [Models::Collection] Collection of user role objects
|
256
264
|
def list_user_roles(page: 1, per_page: 20)
|
257
|
-
get("/user_roles", query: { page: page, per_page: per_page })
|
265
|
+
get("/user_roles", query: { page: page, per_page: per_page }, collection: true)
|
258
266
|
end
|
259
267
|
|
260
268
|
# Get details for a specific user role
|
@@ -269,34 +277,35 @@ module Pylon
|
|
269
277
|
#
|
270
278
|
# @param page [Integer] Page number for pagination
|
271
279
|
# @param per_page [Integer] Number of items per page
|
272
|
-
# @return [
|
280
|
+
# @return [Models::Collection<Models::User>] Collection of user objects
|
273
281
|
def list_users(page: 1, per_page: 20)
|
274
|
-
get("/users", query: { page: page, per_page: per_page }
|
282
|
+
get("/users", query: { page: page, per_page: per_page },
|
283
|
+
model_class: Models::User, collection: true)
|
275
284
|
end
|
276
285
|
|
277
286
|
# Create a new user
|
278
287
|
#
|
279
288
|
# @param params [Hash] User parameters
|
280
|
-
# @return [
|
289
|
+
# @return [Models::User] Created user object
|
281
290
|
def create_user(params)
|
282
|
-
post("/users", body: params)
|
291
|
+
post("/users", body: params, model_class: Models::User)
|
283
292
|
end
|
284
293
|
|
285
294
|
# Get details for a specific user
|
286
295
|
#
|
287
296
|
# @param user_id [String] The ID of the user to retrieve
|
288
|
-
# @return [
|
297
|
+
# @return [Models::User] User object
|
289
298
|
def get_user(user_id)
|
290
|
-
get("/users/#{user_id}")
|
299
|
+
get("/users/#{user_id}", model_class: Models::User)
|
291
300
|
end
|
292
301
|
|
293
302
|
# Update an existing user
|
294
303
|
#
|
295
304
|
# @param user_id [String] The ID of the user to update
|
296
305
|
# @param params [Hash] Updated user parameters
|
297
|
-
# @return [
|
306
|
+
# @return [Models::User] Updated user object
|
298
307
|
def update_user(user_id, params)
|
299
|
-
patch("/users/#{user_id}", body: params)
|
308
|
+
patch("/users/#{user_id}", body: params, model_class: Models::User)
|
300
309
|
end
|
301
310
|
|
302
311
|
private
|
@@ -306,7 +315,7 @@ module Pylon
|
|
306
315
|
@connection ||= Faraday.new(@base_url) do |f|
|
307
316
|
f.request :json
|
308
317
|
f.request :multipart
|
309
|
-
f.response :json
|
318
|
+
f.response :json, content_type: /\bjson$/
|
310
319
|
f.response :logger if @debug
|
311
320
|
f.adapter Faraday.default_adapter
|
312
321
|
f.headers["Authorization"] = "Bearer #{api_key}"
|
@@ -318,31 +327,67 @@ module Pylon
|
|
318
327
|
# Handle API response and raise appropriate errors
|
319
328
|
#
|
320
329
|
# @param response [Faraday::Response] The API response
|
321
|
-
# @
|
330
|
+
# @param model_class [Class] The model class to use for wrapping the response
|
331
|
+
# @param collection [Boolean] Whether the response is a collection of items
|
332
|
+
# @return [Models::Base, Models::Collection, Array] Model, Collection, or response data array
|
322
333
|
# @raise [AuthenticationError] If authentication fails
|
323
334
|
# @raise [ResourceNotFoundError] If resource is not found
|
324
335
|
# @raise [ValidationError] If request parameters are invalid
|
325
336
|
# @raise [ApiError] For other API errors
|
326
|
-
def handle_response(response)
|
337
|
+
def handle_response(response, model_class = nil, collection = false)
|
327
338
|
if @debug
|
328
339
|
puts "Request URL: #{response.env.url}"
|
329
340
|
puts "Response status: #{response.status}"
|
330
341
|
puts "Response body: #{response.body.inspect}"
|
331
342
|
end
|
332
343
|
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
344
|
+
if response.status.between?(200, 299)
|
345
|
+
return handle_successful_response(response, model_class, collection)
|
346
|
+
else
|
347
|
+
handle_error_response(response)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
# Handle successful API response
|
352
|
+
#
|
353
|
+
# @param response [Faraday::Response] The API response
|
354
|
+
# @param model_class [Class] The model class to use for wrapping the response
|
355
|
+
# @param collection [Boolean] Whether the response is a collection of items
|
356
|
+
# @return [Models::Base, Models::Collection, Array] Wrapped response data
|
357
|
+
def handle_successful_response(response, model_class, collection)
|
358
|
+
data = response.body
|
359
|
+
data = data["data"] if data.is_a?(Hash) && data.key?("data")
|
360
|
+
|
361
|
+
if model_class
|
362
|
+
if collection
|
363
|
+
Models::Collection.new(data, model_class, response)
|
364
|
+
else
|
365
|
+
model_class.new(data, response)
|
366
|
+
end
|
367
|
+
else
|
337
368
|
[data, response]
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
# Handle error API response
|
373
|
+
#
|
374
|
+
# @param response [Faraday::Response] The API response
|
375
|
+
# @raise [AuthenticationError] If authentication fails
|
376
|
+
# @raise [ResourceNotFoundError] If resource is not found
|
377
|
+
# @raise [ValidationError] If request parameters are invalid
|
378
|
+
# @raise [ApiError] For other API errors
|
379
|
+
def handle_error_response(response)
|
380
|
+
case response.status
|
338
381
|
when 401
|
339
|
-
raise AuthenticationError, parse_error_message(response)
|
382
|
+
raise AuthenticationError, parse_error_message(response) || "Invalid API key"
|
340
383
|
when 404
|
341
|
-
raise ResourceNotFoundError, parse_error_message(response)
|
384
|
+
raise ResourceNotFoundError, parse_error_message(response) || "Resource not found"
|
342
385
|
when 422
|
343
|
-
raise ValidationError, parse_error_message(response)
|
386
|
+
raise ValidationError, parse_error_message(response) || "Validation error"
|
387
|
+
when 429
|
388
|
+
raise ApiError, parse_error_message(response) || "Rate limit exceeded"
|
344
389
|
else
|
345
|
-
raise ApiError.new(parse_error_message(response), response)
|
390
|
+
raise ApiError.new(parse_error_message(response) || "Internal server error", response)
|
346
391
|
end
|
347
392
|
end
|
348
393
|
|
@@ -351,10 +396,12 @@ module Pylon
|
|
351
396
|
# @param response [Faraday::Response] The API response
|
352
397
|
# @return [String] Error message
|
353
398
|
def parse_error_message(response)
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
399
|
+
return nil unless response.body.is_a?(Hash)
|
400
|
+
|
401
|
+
if response.body["errors"].is_a?(Array) && !response.body["errors"].empty?
|
402
|
+
response.body["errors"].first
|
403
|
+
elsif response.body["error"].is_a?(String)
|
404
|
+
response.body["error"]
|
358
405
|
end
|
359
406
|
end
|
360
407
|
|
@@ -362,35 +409,43 @@ module Pylon
|
|
362
409
|
#
|
363
410
|
# @param path [String] The API endpoint path
|
364
411
|
# @param query [Hash] Query parameters
|
365
|
-
# @
|
366
|
-
|
367
|
-
|
412
|
+
# @param model_class [Class] The model class to use for wrapping the response
|
413
|
+
# @param collection [Boolean] Whether the response is a collection of items
|
414
|
+
# @return [Models::Base, Models::Collection, Array] Model, Collection, or response data array
|
415
|
+
def get(path, query: {}, model_class: nil, collection: false)
|
416
|
+
handle_response(connection.get(path, query), model_class, collection)
|
368
417
|
end
|
369
418
|
|
370
419
|
# Make a POST request
|
371
420
|
#
|
372
421
|
# @param path [String] The API endpoint path
|
373
422
|
# @param body [Hash] Request body
|
374
|
-
# @
|
375
|
-
|
376
|
-
|
423
|
+
# @param model_class [Class] The model class to use for wrapping the response
|
424
|
+
# @param collection [Boolean] Whether the response is a collection of items
|
425
|
+
# @return [Models::Base, Models::Collection, Array] Model, Collection, or response data array
|
426
|
+
def post(path, body: {}, model_class: nil, collection: false)
|
427
|
+
handle_response(connection.post(path, body.to_json), model_class, collection)
|
377
428
|
end
|
378
429
|
|
379
430
|
# Make a PATCH request
|
380
431
|
#
|
381
432
|
# @param path [String] The API endpoint path
|
382
433
|
# @param body [Hash] Request body
|
383
|
-
# @
|
384
|
-
|
385
|
-
|
434
|
+
# @param model_class [Class] The model class to use for wrapping the response
|
435
|
+
# @param collection [Boolean] Whether the response is a collection of items
|
436
|
+
# @return [Models::Base, Models::Collection, Array] Model, Collection, or response data array
|
437
|
+
def patch(path, body: {}, model_class: nil, collection: false)
|
438
|
+
handle_response(connection.patch(path, body.to_json), model_class, collection)
|
386
439
|
end
|
387
440
|
|
388
441
|
# Make a DELETE request
|
389
442
|
#
|
390
443
|
# @param path [String] The API endpoint path
|
391
|
-
# @
|
392
|
-
|
393
|
-
|
444
|
+
# @param model_class [Class] The model class to use for wrapping the response
|
445
|
+
# @param collection [Boolean] Whether the response is a collection of items
|
446
|
+
# @return [Models::Base, Models::Collection, Array] Model, Collection, or response data array
|
447
|
+
def delete(path, model_class: nil, collection: false)
|
448
|
+
handle_response(connection.delete(path), model_class, collection)
|
394
449
|
end
|
395
450
|
end
|
396
|
-
end
|
451
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pylon
|
4
|
+
module Models
|
5
|
+
class Base
|
6
|
+
attr_reader :attributes, :_response
|
7
|
+
|
8
|
+
def initialize(attributes = {}, response = nil)
|
9
|
+
@attributes = attributes || {}
|
10
|
+
@_response = response
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing(method_name, *args, &block)
|
14
|
+
key = method_name.to_s
|
15
|
+
if @attributes.key?(key)
|
16
|
+
@attributes[key]
|
17
|
+
else
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def respond_to_missing?(method_name, include_private = false)
|
23
|
+
@attributes.key?(method_name.to_s) || super
|
24
|
+
end
|
25
|
+
|
26
|
+
def [](key)
|
27
|
+
@attributes[key.to_s]
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_h
|
31
|
+
@attributes
|
32
|
+
end
|
33
|
+
alias to_hash to_h
|
34
|
+
|
35
|
+
def inspect
|
36
|
+
"#<#{self.class.name} #{@attributes.inspect}>"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pylon
|
4
|
+
module Models
|
5
|
+
class Collection
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
attr_reader :items, :_response
|
9
|
+
|
10
|
+
def initialize(items = [], model_class = nil, response = nil)
|
11
|
+
@items = items.map do |item|
|
12
|
+
model_class ? model_class.new(item) : item
|
13
|
+
end
|
14
|
+
@_response = response
|
15
|
+
end
|
16
|
+
|
17
|
+
def each(&block)
|
18
|
+
@items.each(&block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def [](index)
|
22
|
+
@items[index]
|
23
|
+
end
|
24
|
+
|
25
|
+
def size
|
26
|
+
@items.size
|
27
|
+
end
|
28
|
+
alias length size
|
29
|
+
|
30
|
+
def to_a
|
31
|
+
@items
|
32
|
+
end
|
33
|
+
|
34
|
+
def inspect
|
35
|
+
"#<#{self.class.name} items=#{@items.size}>"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/pylon/version.rb
CHANGED
data/lib/pylon.rb
CHANGED
@@ -5,6 +5,17 @@ require "faraday/multipart"
|
|
5
5
|
require "json"
|
6
6
|
|
7
7
|
require_relative "pylon/version"
|
8
|
+
require_relative "pylon/models/base"
|
9
|
+
require_relative "pylon/models/collection"
|
10
|
+
require_relative "pylon/models/user"
|
11
|
+
require_relative "pylon/models/account"
|
12
|
+
require_relative "pylon/models/issue"
|
13
|
+
require_relative "pylon/models/team"
|
14
|
+
require_relative "pylon/models/tag"
|
15
|
+
require_relative "pylon/models/attachment"
|
16
|
+
require_relative "pylon/models/contact"
|
17
|
+
require_relative "pylon/models/ticket_form"
|
18
|
+
require_relative "pylon/models/article"
|
8
19
|
require_relative "pylon/client"
|
9
20
|
|
10
21
|
module Pylon
|
metadata
CHANGED
@@ -1,43 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pylon-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Odom
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 1.10.4
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 1.10.4
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: faraday-multipart
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 1.0.4
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 1.0.4
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: faraday-retry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.0.3
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.0.3
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rake
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -120,6 +134,17 @@ files:
|
|
120
134
|
- README.md
|
121
135
|
- lib/pylon.rb
|
122
136
|
- lib/pylon/client.rb
|
137
|
+
- lib/pylon/models/account.rb
|
138
|
+
- lib/pylon/models/article.rb
|
139
|
+
- lib/pylon/models/attachment.rb
|
140
|
+
- lib/pylon/models/base.rb
|
141
|
+
- lib/pylon/models/collection.rb
|
142
|
+
- lib/pylon/models/contact.rb
|
143
|
+
- lib/pylon/models/issue.rb
|
144
|
+
- lib/pylon/models/tag.rb
|
145
|
+
- lib/pylon/models/team.rb
|
146
|
+
- lib/pylon/models/ticket_form.rb
|
147
|
+
- lib/pylon/models/user.rb
|
123
148
|
- lib/pylon/version.rb
|
124
149
|
- lib/tasks/version.rake
|
125
150
|
homepage: https://github.com/benjodo/pylon-api
|