monday_ruby 1.0.0 → 1.2.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 (93) hide show
  1. checksums.yaml +4 -4
  2. data/.env +1 -1
  3. data/.rspec +0 -1
  4. data/.rubocop.yml +19 -0
  5. data/.simplecov +1 -0
  6. data/CHANGELOG.md +49 -0
  7. data/CONTRIBUTING.md +165 -0
  8. data/README.md +167 -88
  9. data/docs/.vitepress/config.mjs +255 -0
  10. data/docs/.vitepress/theme/index.js +4 -0
  11. data/docs/.vitepress/theme/style.css +43 -0
  12. data/docs/README.md +80 -0
  13. data/docs/explanation/architecture.md +507 -0
  14. data/docs/explanation/best-practices/errors.md +478 -0
  15. data/docs/explanation/best-practices/performance.md +1084 -0
  16. data/docs/explanation/best-practices/rate-limiting.md +630 -0
  17. data/docs/explanation/best-practices/testing.md +820 -0
  18. data/docs/explanation/column-values.md +857 -0
  19. data/docs/explanation/design.md +795 -0
  20. data/docs/explanation/graphql.md +356 -0
  21. data/docs/explanation/migration/v1.md +808 -0
  22. data/docs/explanation/pagination.md +447 -0
  23. data/docs/guides/advanced/batch.md +1274 -0
  24. data/docs/guides/advanced/complex-queries.md +1114 -0
  25. data/docs/guides/advanced/errors.md +818 -0
  26. data/docs/guides/advanced/pagination.md +934 -0
  27. data/docs/guides/advanced/rate-limiting.md +981 -0
  28. data/docs/guides/authentication.md +286 -0
  29. data/docs/guides/boards/create.md +386 -0
  30. data/docs/guides/boards/delete.md +405 -0
  31. data/docs/guides/boards/duplicate.md +511 -0
  32. data/docs/guides/boards/query.md +530 -0
  33. data/docs/guides/boards/update.md +453 -0
  34. data/docs/guides/columns/create.md +452 -0
  35. data/docs/guides/columns/metadata.md +492 -0
  36. data/docs/guides/columns/query.md +455 -0
  37. data/docs/guides/columns/update-multiple.md +459 -0
  38. data/docs/guides/columns/update-values.md +509 -0
  39. data/docs/guides/files/add-to-column.md +40 -0
  40. data/docs/guides/files/add-to-update.md +37 -0
  41. data/docs/guides/files/clear-column.md +33 -0
  42. data/docs/guides/first-request.md +285 -0
  43. data/docs/guides/folders/manage.md +750 -0
  44. data/docs/guides/groups/items.md +626 -0
  45. data/docs/guides/groups/manage.md +501 -0
  46. data/docs/guides/installation.md +169 -0
  47. data/docs/guides/items/create.md +493 -0
  48. data/docs/guides/items/delete.md +514 -0
  49. data/docs/guides/items/query.md +605 -0
  50. data/docs/guides/items/subitems.md +483 -0
  51. data/docs/guides/items/update.md +699 -0
  52. data/docs/guides/updates/manage.md +619 -0
  53. data/docs/guides/use-cases/dashboard.md +1421 -0
  54. data/docs/guides/use-cases/import.md +1962 -0
  55. data/docs/guides/use-cases/task-management.md +1381 -0
  56. data/docs/guides/workspaces/manage.md +502 -0
  57. data/docs/index.md +69 -0
  58. data/docs/package-lock.json +2468 -0
  59. data/docs/package.json +13 -0
  60. data/docs/reference/client.md +540 -0
  61. data/docs/reference/configuration.md +586 -0
  62. data/docs/reference/errors.md +693 -0
  63. data/docs/reference/resources/account.md +208 -0
  64. data/docs/reference/resources/activity-log.md +369 -0
  65. data/docs/reference/resources/board-view.md +359 -0
  66. data/docs/reference/resources/board.md +393 -0
  67. data/docs/reference/resources/column.md +543 -0
  68. data/docs/reference/resources/file.md +236 -0
  69. data/docs/reference/resources/folder.md +386 -0
  70. data/docs/reference/resources/group.md +507 -0
  71. data/docs/reference/resources/item.md +348 -0
  72. data/docs/reference/resources/subitem.md +267 -0
  73. data/docs/reference/resources/update.md +259 -0
  74. data/docs/reference/resources/workspace.md +213 -0
  75. data/docs/reference/response.md +560 -0
  76. data/docs/tutorial/first-integration.md +713 -0
  77. data/lib/monday/client.rb +41 -2
  78. data/lib/monday/configuration.rb +13 -0
  79. data/lib/monday/deprecation.rb +23 -0
  80. data/lib/monday/error.rb +5 -2
  81. data/lib/monday/request.rb +19 -1
  82. data/lib/monday/resources/base.rb +4 -0
  83. data/lib/monday/resources/board.rb +52 -0
  84. data/lib/monday/resources/column.rb +6 -0
  85. data/lib/monday/resources/file.rb +56 -0
  86. data/lib/monday/resources/folder.rb +55 -0
  87. data/lib/monday/resources/group.rb +66 -0
  88. data/lib/monday/resources/item.rb +62 -0
  89. data/lib/monday/util.rb +33 -1
  90. data/lib/monday/version.rb +1 -1
  91. data/lib/monday_ruby.rb +1 -0
  92. metadata +92 -11
  93. data/monday_ruby.gemspec +0 -39
@@ -0,0 +1,447 @@
1
+ # Pagination in monday.com
2
+
3
+ This document explains pagination concepts and how they apply to the monday.com API and the monday_ruby gem.
4
+
5
+ ## What is Pagination?
6
+
7
+ Pagination is the practice of dividing large datasets into smaller, manageable chunks called "pages." Instead of retrieving thousands of records in a single API request, pagination allows you to fetch data incrementally.
8
+
9
+ ### Why Pagination is Necessary
10
+
11
+ 1. **Performance**: Loading thousands of items at once would be slow for both the server and client
12
+ 2. **Memory**: Large datasets can exhaust available memory, especially on mobile devices
13
+ 3. **Timeout prevention**: Long-running requests risk timing out before completion
14
+ 4. **User experience**: Users can see results immediately rather than waiting for everything to load
15
+ 5. **Network efficiency**: Smaller responses are faster to transmit and more resilient to connection issues
16
+ 6. **Rate limiting**: Spreading requests across time helps stay within API rate limits
17
+
18
+ ### The Alternative
19
+
20
+ Without pagination, fetching all items from a board with 10,000 items would:
21
+ - Take 10+ seconds to complete
22
+ - Use several megabytes of bandwidth
23
+ - Risk timeout on slower connections
24
+ - Potentially hit API complexity limits
25
+ - Load data users may never view
26
+
27
+ ## Cursor-Based vs Offset-Based Pagination
28
+
29
+ There are two primary pagination strategies, each with distinct trade-offs.
30
+
31
+ ### Offset-Based Pagination
32
+
33
+ Uses numeric offsets to specify starting positions:
34
+
35
+ ```
36
+ GET /items?offset=0&limit=25 # First page
37
+ GET /items?offset=25&limit=25 # Second page
38
+ GET /items?offset=50&limit=25 # Third page
39
+ ```
40
+
41
+ **Advantages**:
42
+ - Simple to understand and implement
43
+ - Direct access to any page (e.g., "jump to page 5")
44
+ - Easy to calculate total pages
45
+
46
+ **Disadvantages**:
47
+ - Inconsistent results if data changes between requests (items added/deleted)
48
+ - Inefficient for large offsets (database must skip many rows)
49
+ - Difficult to handle concurrent modifications
50
+ - "Page drift" when items are added/removed during pagination
51
+
52
+ **Example of page drift**:
53
+ ```
54
+ Initial state: [A, B, C, D, E, F, G, H]
55
+
56
+ Request 1 (offset=0, limit=3): Returns [A, B, C]
57
+ New item X inserted at position 0: [X, A, B, C, D, E, F, G, H]
58
+ Request 2 (offset=3, limit=3): Returns [C, D, E]
59
+ Result: Item C appears twice, B is skipped
60
+ ```
61
+
62
+ ### Cursor-Based Pagination
63
+
64
+ Uses opaque tokens (cursors) to mark positions in a dataset:
65
+
66
+ ```
67
+ GET /items?cursor=initial&limit=25
68
+ # Response includes next_cursor: "eyJpZCI6MTIzfQ=="
69
+
70
+ GET /items?cursor=eyJpZCI6MTIzfQ==&limit=25
71
+ # Response includes next_cursor: "eyJpZCI6MTQ4fQ=="
72
+ ```
73
+
74
+ **Advantages**:
75
+ - Consistent results even when data changes
76
+ - Efficient at any depth in the dataset
77
+ - Handles concurrent modifications gracefully
78
+ - No duplicate or skipped items
79
+
80
+ **Disadvantages**:
81
+ - Cannot jump to arbitrary pages
82
+ - Cannot calculate total page count easily
83
+ - Cursors can become invalid
84
+ - More complex implementation
85
+
86
+ ## Why monday.com Uses Cursor-Based Pagination
87
+
88
+ monday.com adopted cursor-based pagination for several architectural reasons:
89
+
90
+ ### Real-Time Collaboration
91
+
92
+ monday.com is a collaborative platform where multiple users modify boards simultaneously:
93
+ - Items are created and deleted constantly
94
+ - Items move between groups
95
+ - Board structure changes frequently
96
+
97
+ Cursor-based pagination ensures that when you're iterating through items, you get a consistent view even as the board changes.
98
+
99
+ ### Scalability
100
+
101
+ Large boards can have tens of thousands of items. Cursor-based pagination:
102
+ - Maintains consistent performance regardless of position in the dataset
103
+ - Uses database indexes efficiently
104
+ - Avoids expensive offset calculations
105
+
106
+ ### API Design Philosophy
107
+
108
+ monday.com's GraphQL API emphasizes:
109
+ - **Reliability**: Cursors prevent duplicate or missed items
110
+ - **Efficiency**: Each request is optimized for the current state
111
+ - **Consistency**: The same cursor always points to the same logical position
112
+
113
+ ## How Cursor Pagination Works
114
+
115
+ ### Opaque Cursors
116
+
117
+ Cursors in monday.com are opaque strings - their internal structure is implementation-dependent and subject to change. A cursor might encode:
118
+ - Item ID
119
+ - Timestamp
120
+ - Sort order
121
+ - Filter criteria
122
+
123
+ **Important**: Treat cursors as opaque tokens. Never:
124
+ - Parse or decode cursors
125
+ - Construct cursors manually
126
+ - Make assumptions about cursor format
127
+ - Store cursors long-term
128
+
129
+ ### Pagination Flow
130
+
131
+ 1. **Initial request**: Don't provide a cursor
132
+ ```ruby
133
+ response = client.item.items_page(
134
+ args: { limit: 25, query_params: { boards: [123] } }
135
+ )
136
+ ```
137
+
138
+ 2. **Extract cursor**: Get the cursor from the response
139
+ ```ruby
140
+ cursor = response.dig("data", "items_page", "cursor")
141
+ ```
142
+
143
+ 3. **Subsequent requests**: Pass the cursor to get the next page
144
+ ```ruby
145
+ next_page = client.item.items_page(
146
+ args: { limit: 25, cursor: cursor, query_params: { boards: [123] } }
147
+ )
148
+ ```
149
+
150
+ 4. **Detect end**: When there's no more data, the cursor may be nil or empty
151
+
152
+ ### Cursor Characteristics
153
+
154
+ - **Stateful**: Encodes position in a specific query result set
155
+ - **Query-specific**: A cursor from one query won't work with a different query
156
+ - **Time-sensitive**: Cursors expire after a certain period
157
+ - **Opaque**: Internal format is not guaranteed or documented
158
+ - **Forward-only**: Can only move forward through results
159
+
160
+ ## Cursor Expiration
161
+
162
+ monday.com cursors expire after **60 minutes** of inactivity.
163
+
164
+ ### Why Cursors Expire
165
+
166
+ 1. **Resource management**: Servers don't maintain pagination state indefinitely
167
+ 2. **Data consistency**: Prevents using stale cursors on significantly changed data
168
+ 3. **Security**: Limits the window for cursor-based attacks or abuse
169
+ 4. **Cache invalidation**: Allows backend caches to be cleared periodically
170
+
171
+ ### Handling Expiration
172
+
173
+ When a cursor expires:
174
+ - The API returns an error indicating the cursor is invalid
175
+ - You must restart pagination from the beginning
176
+ - Previously fetched data remains valid
177
+
178
+ ### Best Practices
179
+
180
+ - **Process promptly**: Don't hold cursors for extended periods
181
+ - **Handle errors**: Detect expired cursor errors and restart
182
+ - **Avoid storing**: Don't persist cursors in databases or long-term storage
183
+ - **Complete iterations**: Finish paginating through results in a single session when possible
184
+
185
+ ### Expiration Example
186
+
187
+ ```ruby
188
+ # Start pagination at 10:00 AM
189
+ cursor = get_first_page_cursor()
190
+
191
+ # Wait 65 minutes...
192
+
193
+ # Use cursor at 11:05 AM - will fail!
194
+ begin
195
+ next_page = get_page(cursor)
196
+ rescue Monday::InvalidCursorError
197
+ # Cursor expired, restart pagination
198
+ cursor = get_first_page_cursor()
199
+ next_page = get_page(cursor)
200
+ end
201
+ ```
202
+
203
+ ## Pagination Performance Considerations
204
+
205
+ ### Page Size Trade-offs
206
+
207
+ Choosing the right page size (limit parameter) involves balancing competing factors:
208
+
209
+ **Small pages (e.g., 10-25 items)**:
210
+ - Lower latency per request
211
+ - Less memory usage
212
+ - More requests needed to fetch all data
213
+ - Higher total time for complete dataset
214
+ - More API calls (impacts rate limits)
215
+
216
+ **Large pages (e.g., 100-500 items)**:
217
+ - Higher latency per request
218
+ - More memory usage
219
+ - Fewer requests needed
220
+ - Lower total time for complete dataset
221
+ - Fewer API calls
222
+
223
+ **Optimal page size depends on**:
224
+ - Network speed and reliability
225
+ - Available memory
226
+ - UI/UX requirements (how much to show at once)
227
+ - Rate limit constraints
228
+ - Total dataset size
229
+
230
+ ### monday.com Limits
231
+
232
+ monday.com enforces limits on page size:
233
+ - Maximum items per page varies by endpoint
234
+ - Typically capped at 100-500 items
235
+ - Larger limits consume more API complexity budget
236
+
237
+ ### Network Efficiency
238
+
239
+ Cursor-based pagination is network-efficient:
240
+ - Only requested data is transmitted
241
+ - Subsequent requests reuse connection pooling
242
+ - Cursors are small (typically under 100 bytes)
243
+ - Partial failures can be retried from last successful cursor
244
+
245
+ ### Caching Considerations
246
+
247
+ Cursor-based pagination affects caching strategies:
248
+ - Individual pages can be cached using cursor as key
249
+ - Cache expiration should align with cursor expiration (60 minutes)
250
+ - First page (no cursor) is often most heavily cached
251
+ - Personalized or filtered queries are harder to cache
252
+
253
+ ## items_page vs Deprecated items Field
254
+
255
+ monday.com's GraphQL API has evolved its pagination approach.
256
+
257
+ ### Legacy: items Field
258
+
259
+ The original `items` field on boards returned all items without pagination:
260
+
261
+ ```graphql
262
+ query {
263
+ boards(ids: [123]) {
264
+ items {
265
+ id
266
+ name
267
+ }
268
+ }
269
+ }
270
+ ```
271
+
272
+ **Problems**:
273
+ - No pagination support
274
+ - Returns all items at once
275
+ - Performance degrades with large boards
276
+ - Timeout risk on boards with many items
277
+ - High API complexity cost
278
+
279
+ ### Modern: items_page Query
280
+
281
+ The `items_page` query provides cursor-based pagination:
282
+
283
+ ```graphql
284
+ query {
285
+ items_page(limit: 25, query_params: {boards: [123]}) {
286
+ cursor
287
+ items {
288
+ id
289
+ name
290
+ }
291
+ }
292
+ }
293
+ ```
294
+
295
+ **Advantages**:
296
+ - Efficient pagination with cursors
297
+ - Consistent performance regardless of board size
298
+ - Lower complexity per request
299
+ - Better resource utilization
300
+ - Query parameters for filtering
301
+
302
+ ### Migration Path
303
+
304
+ monday.com deprecated the `items` field to encourage pagination:
305
+ - New applications should use `items_page`
306
+ - Existing applications should migrate to avoid deprecation
307
+ - The `items` field may be removed in future API versions
308
+
309
+ The monday_ruby gem provides methods for both:
310
+ - `client.board.items` - legacy (deprecated)
311
+ - `client.item.items_page` - modern (recommended)
312
+
313
+ ## Query Parameters and Filtering with Pagination
314
+
315
+ The `items_page` query supports filtering through query parameters, which interact with pagination in important ways.
316
+
317
+ ### Query Parameters
318
+
319
+ Common filters include:
320
+ - `boards`: Limit to specific boards
321
+ - `state`: Filter by item state (active, archived, deleted)
322
+ - `order_by`: Sort order for results
323
+
324
+ ```ruby
325
+ client.item.items_page(
326
+ args: {
327
+ limit: 25,
328
+ query_params: {
329
+ boards: [123, 456],
330
+ state: "active",
331
+ order_by: [{ column_id: "date", direction: "desc" }]
332
+ }
333
+ }
334
+ )
335
+ ```
336
+
337
+ ### Cursor-Filter Coupling
338
+
339
+ Cursors are tied to their query parameters:
340
+ - A cursor from a filtered query only works with the same filter
341
+ - Changing `query_params` invalidates the cursor
342
+ - The cursor encodes both position and query context
343
+
344
+ **Example of what NOT to do**:
345
+ ```ruby
346
+ # Request 1: Filter by board 123
347
+ response1 = items_page(query_params: { boards: [123] })
348
+ cursor = response1["cursor"]
349
+
350
+ # Request 2: Try to use cursor with different filter - ERROR!
351
+ response2 = items_page(cursor: cursor, query_params: { boards: [456] })
352
+ # This will fail - cursor is specific to board 123
353
+ ```
354
+
355
+ ### Filtering Best Practices
356
+
357
+ 1. **Keep filters consistent**: Use identical `query_params` throughout pagination
358
+ 2. **Filter early**: Apply filters in the initial request, not on fetched results
359
+ 3. **Understand costs**: Complex filters may increase API complexity
360
+ 4. **Combine operations**: Fetch and filter in a single request rather than multiple
361
+
362
+ ### Pagination with Sorting
363
+
364
+ When using `order_by`, cursors maintain the sort order:
365
+ - Results remain sorted across all pages
366
+ - Cursor position is relative to the sorted sequence
367
+ - Changing sort order invalidates the cursor
368
+
369
+ ## Trade-offs: Page Size vs API Calls
370
+
371
+ Determining optimal pagination strategy requires analyzing multiple dimensions.
372
+
373
+ ### Scenario 1: Display 25 Items to User
374
+
375
+ If you only need to show 25 items:
376
+ - Set `limit: 25`
377
+ - Make 1 API call
378
+ - Minimal complexity
379
+ - Fastest time-to-display
380
+
381
+ ### Scenario 2: Process All 1,000 Items
382
+
383
+ If you need to process every item on a board:
384
+
385
+ **Option A: Small pages (25 items)**
386
+ - 40 API calls required
387
+ - 40× authentication overhead
388
+ - 40× network round-trips
389
+ - Lower memory footprint
390
+ - Can start processing sooner
391
+ - More resilient to failures (restart from last cursor)
392
+
393
+ **Option B: Large pages (100 items)**
394
+ - 10 API calls required
395
+ - 10× authentication overhead
396
+ - 10× network round-trips
397
+ - Higher memory footprint
398
+ - Longer wait before processing starts
399
+ - More data lost on failure
400
+
401
+ ### Scenario 3: Rate-Limited Environment
402
+
403
+ If you're close to rate limits:
404
+ - Larger pages reduce total API calls
405
+ - But larger pages have higher complexity per call
406
+ - Must balance: fewer calls vs complexity budget
407
+ - May need to add delays between requests
408
+
409
+ ### Scenario 4: Real-Time Updates
410
+
411
+ If displaying data as it loads:
412
+ - Smaller pages provide faster initial display
413
+ - Users see results immediately
414
+ - Can implement infinite scroll or "load more"
415
+ - Better perceived performance
416
+
417
+ ### Calculation Example
418
+
419
+ Board with 1,000 items, rate limit of 100 requests/minute:
420
+
421
+ **25-item pages**:
422
+ - Requests needed: 40
423
+ - Time at max rate: 24 seconds (within limit)
424
+ - Memory per page: ~25 KB
425
+ - Total transfer: ~1 MB
426
+
427
+ **100-item pages**:
428
+ - Requests needed: 10
429
+ - Time at max rate: 6 seconds
430
+ - Memory per page: ~100 KB
431
+ - Total transfer: ~1 MB
432
+
433
+ Same total data transferred, but different time and memory profiles.
434
+
435
+ ## Conclusion
436
+
437
+ Pagination is a fundamental aspect of working with the monday.com API. Understanding cursor-based pagination - its advantages over offset pagination, how cursors work, their expiration behavior, and the trade-offs in page sizing - is essential for building efficient, reliable applications.
438
+
439
+ Key takeaways:
440
+ - monday.com uses cursor-based pagination for consistency and performance
441
+ - Cursors are opaque, stateful, and expire after 60 minutes
442
+ - Use `items_page` instead of the deprecated `items` field
443
+ - Page size involves trade-offs between latency, memory, and API calls
444
+ - Query parameters must remain consistent throughout pagination
445
+ - Proper pagination design significantly impacts application performance and user experience
446
+
447
+ The monday_ruby gem abstracts the mechanics of cursor handling while preserving GraphQL's pagination semantics, but understanding these underlying concepts enables you to make informed decisions about pagination strategy in your applications.