finch-api 0.1.0.pre.alpha.16 → 0.1.0.pre.alpha.18

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 (164) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -0
  3. data/README.md +92 -53
  4. data/lib/finch_api/client.rb +4 -4
  5. data/lib/finch_api/errors.rb +1 -1
  6. data/lib/finch_api/internal/transport/base_client.rb +77 -5
  7. data/lib/finch_api/internal/transport/pooled_net_requester.rb +17 -1
  8. data/lib/finch_api/internal/type/array_of.rb +1 -1
  9. data/lib/finch_api/internal/type/base_model.rb +70 -30
  10. data/lib/finch_api/internal/type/converter.rb +18 -0
  11. data/lib/finch_api/internal/type/enum.rb +1 -0
  12. data/lib/finch_api/internal/type/hash_of.rb +1 -1
  13. data/lib/finch_api/internal/type/union.rb +1 -0
  14. data/lib/finch_api/internal/util.rb +56 -0
  15. data/lib/finch_api/internal.rb +6 -0
  16. data/lib/finch_api/models/hris/document_retreive_response.rb +4 -0
  17. data/lib/finch_api/models/hris/employment_data.rb +19 -9
  18. data/lib/finch_api/models/hris/individual.rb +6 -0
  19. data/lib/finch_api/models/hris/pay_statement.rb +1 -0
  20. data/lib/finch_api/models/sandbox/payment_create_params.rb +1 -0
  21. data/lib/finch_api/models/webhook_event.rb +15 -0
  22. data/lib/finch_api/models.rb +27 -0
  23. data/lib/finch_api/request_options.rb +4 -0
  24. data/lib/finch_api/version.rb +1 -1
  25. data/lib/finch_api.rb +2 -0
  26. data/rbi/finch_api/internal/transport/base_client.rbi +31 -16
  27. data/rbi/finch_api/internal/transport/pooled_net_requester.rbi +10 -5
  28. data/rbi/finch_api/internal/type/base_model.rbi +33 -15
  29. data/rbi/finch_api/internal/type/base_page.rbi +1 -2
  30. data/rbi/finch_api/internal/type/converter.rbi +2 -0
  31. data/rbi/finch_api/internal/type/enum.rbi +1 -0
  32. data/rbi/finch_api/internal/type/union.rbi +1 -0
  33. data/rbi/finch_api/internal/util.rbi +28 -5
  34. data/rbi/finch_api/internal.rbi +2 -0
  35. data/rbi/finch_api/models/access_token_create_params.rbi +4 -1
  36. data/rbi/finch_api/models/account_disconnect_params.rbi +4 -1
  37. data/rbi/finch_api/models/account_introspect_params.rbi +4 -1
  38. data/rbi/finch_api/models/account_update_event.rbi +156 -34
  39. data/rbi/finch_api/models/base_webhook_event.rbi +4 -1
  40. data/rbi/finch_api/models/company_event.rbi +4 -1
  41. data/rbi/finch_api/models/connect/session_new_params.rbi +12 -2
  42. data/rbi/finch_api/models/connect/session_new_response.rbi +6 -1
  43. data/rbi/finch_api/models/connect/session_reauthenticate_params.rbi +6 -1
  44. data/rbi/finch_api/models/connect/session_reauthenticate_response.rbi +6 -1
  45. data/rbi/finch_api/models/create_access_token_response.rbi +7 -1
  46. data/rbi/finch_api/models/directory_event.rbi +7 -2
  47. data/rbi/finch_api/models/disconnect_response.rbi +4 -1
  48. data/rbi/finch_api/models/employment_event.rbi +7 -2
  49. data/rbi/finch_api/models/hris/benefit_contribution.rbi +6 -1
  50. data/rbi/finch_api/models/hris/benefit_create_params.rbi +18 -3
  51. data/rbi/finch_api/models/hris/benefit_features_and_operations.rbi +12 -2
  52. data/rbi/finch_api/models/hris/benefit_list_params.rbi +6 -1
  53. data/rbi/finch_api/models/hris/benefit_list_supported_benefits_params.rbi +6 -1
  54. data/rbi/finch_api/models/hris/benefit_list_supported_benefits_response.rbi +6 -1
  55. data/rbi/finch_api/models/hris/benefit_retrieve_params.rbi +6 -1
  56. data/rbi/finch_api/models/hris/benefit_update_params.rbi +6 -1
  57. data/rbi/finch_api/models/hris/benefits/enrolled_individual_benefit_response.rbi +6 -1
  58. data/rbi/finch_api/models/hris/benefits/individual_benefit.rbi +12 -2
  59. data/rbi/finch_api/models/hris/benefits/individual_enroll_many_params.rbi +26 -5
  60. data/rbi/finch_api/models/hris/benefits/individual_enrolled_ids_params.rbi +6 -1
  61. data/rbi/finch_api/models/hris/benefits/individual_enrolled_ids_response.rbi +6 -1
  62. data/rbi/finch_api/models/hris/benefits/individual_retrieve_many_benefits_params.rbi +6 -1
  63. data/rbi/finch_api/models/hris/benefits/individual_unenroll_many_params.rbi +6 -1
  64. data/rbi/finch_api/models/hris/benefits/unenrolled_individual_benefit_response.rbi +6 -1
  65. data/rbi/finch_api/models/hris/benefits_support.rbi +3 -1
  66. data/rbi/finch_api/models/hris/company/pay_statement_item/rule_create_params.rbi +18 -3
  67. data/rbi/finch_api/models/hris/company/pay_statement_item/rule_create_response.rbi +18 -3
  68. data/rbi/finch_api/models/hris/company/pay_statement_item/rule_delete_params.rbi +6 -1
  69. data/rbi/finch_api/models/hris/company/pay_statement_item/rule_delete_response.rbi +18 -3
  70. data/rbi/finch_api/models/hris/company/pay_statement_item/rule_list_params.rbi +6 -1
  71. data/rbi/finch_api/models/hris/company/pay_statement_item/rule_list_response.rbi +18 -3
  72. data/rbi/finch_api/models/hris/company/pay_statement_item/rule_update_params.rbi +6 -1
  73. data/rbi/finch_api/models/hris/company/pay_statement_item/rule_update_response.rbi +18 -3
  74. data/rbi/finch_api/models/hris/company/pay_statement_item_list_params.rbi +6 -1
  75. data/rbi/finch_api/models/hris/company/pay_statement_item_list_response.rbi +12 -2
  76. data/rbi/finch_api/models/hris/company.rbi +27 -5
  77. data/rbi/finch_api/models/hris/company_benefit.rbi +15 -3
  78. data/rbi/finch_api/models/hris/company_retrieve_params.rbi +6 -1
  79. data/rbi/finch_api/models/hris/create_company_benefits_response.rbi +6 -1
  80. data/rbi/finch_api/models/hris/directory_list_individuals_params.rbi +6 -1
  81. data/rbi/finch_api/models/hris/directory_list_params.rbi +6 -1
  82. data/rbi/finch_api/models/hris/document_list_params.rbi +6 -1
  83. data/rbi/finch_api/models/hris/document_list_response.rbi +6 -1
  84. data/rbi/finch_api/models/hris/document_response.rbi +3 -1
  85. data/rbi/finch_api/models/hris/document_retreive_params.rbi +6 -1
  86. data/rbi/finch_api/models/hris/employment_data.rbi +48 -17
  87. data/rbi/finch_api/models/hris/employment_data_response.rbi +6 -1
  88. data/rbi/finch_api/models/hris/employment_retrieve_many_params.rbi +12 -2
  89. data/rbi/finch_api/models/hris/individual.rbi +24 -4
  90. data/rbi/finch_api/models/hris/individual_in_directory.rbi +18 -3
  91. data/rbi/finch_api/models/hris/individual_response.rbi +6 -1
  92. data/rbi/finch_api/models/hris/individual_retrieve_many_params.rbi +18 -3
  93. data/rbi/finch_api/models/hris/pay_statement.rbi +80 -13
  94. data/rbi/finch_api/models/hris/pay_statement_response.rbi +6 -1
  95. data/rbi/finch_api/models/hris/pay_statement_response_body.rbi +6 -1
  96. data/rbi/finch_api/models/hris/pay_statement_retrieve_many_params.rbi +12 -2
  97. data/rbi/finch_api/models/hris/payment.rbi +9 -2
  98. data/rbi/finch_api/models/hris/payment_list_params.rbi +6 -1
  99. data/rbi/finch_api/models/hris/support_per_benefit_type.rbi +6 -1
  100. data/rbi/finch_api/models/hris/supported_benefit.rbi +3 -1
  101. data/rbi/finch_api/models/hris/update_company_benefit_response.rbi +6 -1
  102. data/rbi/finch_api/models/hris/w42005.rbi +6 -2
  103. data/rbi/finch_api/models/hris/w42020.rbi +6 -2
  104. data/rbi/finch_api/models/income.rbi +2 -1
  105. data/rbi/finch_api/models/individual_event.rbi +7 -2
  106. data/rbi/finch_api/models/introspection.rbi +22 -4
  107. data/rbi/finch_api/models/job_completion_event.rbi +10 -2
  108. data/rbi/finch_api/models/jobs/automated_async_job.rbi +12 -2
  109. data/rbi/finch_api/models/jobs/automated_create_params.rbi +12 -2
  110. data/rbi/finch_api/models/jobs/automated_create_response.rbi +6 -1
  111. data/rbi/finch_api/models/jobs/automated_list_params.rbi +6 -1
  112. data/rbi/finch_api/models/jobs/automated_list_response.rbi +24 -4
  113. data/rbi/finch_api/models/jobs/automated_retrieve_params.rbi +6 -1
  114. data/rbi/finch_api/models/jobs/manual_async_job.rbi +3 -1
  115. data/rbi/finch_api/models/jobs/manual_retrieve_params.rbi +6 -1
  116. data/rbi/finch_api/models/location.rbi +2 -1
  117. data/rbi/finch_api/models/money.rbi +2 -1
  118. data/rbi/finch_api/models/operation_support_matrix.rbi +4 -1
  119. data/rbi/finch_api/models/paging.rbi +2 -1
  120. data/rbi/finch_api/models/pay_statement_event.rbi +10 -2
  121. data/rbi/finch_api/models/payment_event.rbi +7 -2
  122. data/rbi/finch_api/models/payroll/pay_group_list_params.rbi +6 -1
  123. data/rbi/finch_api/models/payroll/pay_group_list_response.rbi +6 -1
  124. data/rbi/finch_api/models/payroll/pay_group_retrieve_params.rbi +6 -1
  125. data/rbi/finch_api/models/payroll/pay_group_retrieve_response.rbi +6 -1
  126. data/rbi/finch_api/models/provider.rbi +182 -33
  127. data/rbi/finch_api/models/provider_list_params.rbi +4 -1
  128. data/rbi/finch_api/models/request_forwarding_forward_params.rbi +7 -1
  129. data/rbi/finch_api/models/request_forwarding_forward_response.rbi +13 -2
  130. data/rbi/finch_api/models/sandbox/company_update_params.rbi +30 -5
  131. data/rbi/finch_api/models/sandbox/company_update_response.rbi +30 -5
  132. data/rbi/finch_api/models/sandbox/connection_create_params.rbi +6 -1
  133. data/rbi/finch_api/models/sandbox/connection_create_response.rbi +6 -1
  134. data/rbi/finch_api/models/sandbox/connections/account_create_params.rbi +6 -1
  135. data/rbi/finch_api/models/sandbox/connections/account_create_response.rbi +6 -1
  136. data/rbi/finch_api/models/sandbox/connections/account_update_params.rbi +6 -1
  137. data/rbi/finch_api/models/sandbox/connections/account_update_response.rbi +6 -1
  138. data/rbi/finch_api/models/sandbox/directory_create_params.rbi +48 -8
  139. data/rbi/finch_api/models/sandbox/employment_update_params.rbi +30 -5
  140. data/rbi/finch_api/models/sandbox/employment_update_response.rbi +30 -5
  141. data/rbi/finch_api/models/sandbox/individual_update_params.rbi +18 -3
  142. data/rbi/finch_api/models/sandbox/individual_update_response.rbi +18 -3
  143. data/rbi/finch_api/models/sandbox/job_create_params.rbi +6 -1
  144. data/rbi/finch_api/models/sandbox/job_create_response.rbi +6 -1
  145. data/rbi/finch_api/models/sandbox/jobs/configuration_retrieve_params.rbi +6 -1
  146. data/rbi/finch_api/models/sandbox/jobs/configuration_update_params.rbi +6 -1
  147. data/rbi/finch_api/models/sandbox/jobs/sandbox_job_configuration.rbi +6 -1
  148. data/rbi/finch_api/models/sandbox/payment_create_params.rbi +81 -14
  149. data/rbi/finch_api/models/sandbox/payment_create_response.rbi +6 -1
  150. data/rbi/finch_api/request_options.rbi +4 -1
  151. data/sig/finch_api/internal/single_page.rbs +1 -1
  152. data/sig/finch_api/internal/transport/base_client.rbs +16 -1
  153. data/sig/finch_api/internal/transport/pooled_net_requester.rbs +4 -0
  154. data/sig/finch_api/internal/type/base_model.rbs +11 -5
  155. data/sig/finch_api/internal/type/base_page.rbs +1 -1
  156. data/sig/finch_api/internal/type/converter.rbs +2 -0
  157. data/sig/finch_api/internal/type/enum.rbs +1 -0
  158. data/sig/finch_api/internal/type/union.rbs +1 -0
  159. data/sig/finch_api/internal/util.rbs +13 -0
  160. data/sig/finch_api/internal.rbs +2 -0
  161. data/sig/finch_api/models/hris/employment_data.rbs +6 -6
  162. data/sig/finch_api/models/hris/pay_statement.rbs +2 -1
  163. data/sig/finch_api/models/sandbox/payment_create_params.rbs +2 -1
  164. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1601a6acec9c8ee9ff37dba36865d125686acd1130860791c4be9e773e5c752f
4
- data.tar.gz: 6e72ea02606bfaaceb8704ed36aa20fff6762aea697008ecec062d3b7934a303
3
+ metadata.gz: eddfa1529c8cfb3c7461b7553fc9ccebd1818115e88bd4a5a733dbcffad435d4
4
+ data.tar.gz: 37306b10b432110b7b3ce09d4cd245b97b1dd16fe467b050e78a5a2101e18839
5
5
  SHA512:
6
- metadata.gz: f6eeb288c3e80322993f292c404e033eb9d34fa8997eee649bb04b5c6d65ea5929f01689c888806f91de433281d9743df8a80bf8ae7e486cb31cce59e61aa710
7
- data.tar.gz: 7cc012e9a00aeddd02db90efe54f495d205faea60a043de6f1482ff6b0b5d18d259aa02383b376bcd53dc41fa71b2cd814ce5f98386393e23a833b021d428913
6
+ metadata.gz: 40f142561b69c398322f65338f567b6d7ed4e5c059ee067aaeddb2566be1ef3b1f19d9eac8bb635540cea61f1e1e63815020af5b3dc7ca9a920f8202f42d0a6f
7
+ data.tar.gz: 6cf31655554a967db22163906ae8ea254457761f706ea5cdb5d1dbaf920bd4e55c72e4606525bbac868ec3e7b5b38c6c6135b48727f4e0ff717f9acad778bab9
data/CHANGELOG.md CHANGED
@@ -1,5 +1,48 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.0-alpha.18 (2025-05-16)
4
+
5
+ Full Changelog: [v0.1.0-alpha.17...v0.1.0-alpha.18](https://github.com/Finch-API/finch-api-ruby/compare/v0.1.0-alpha.17...v0.1.0-alpha.18)
6
+
7
+ ### Features
8
+
9
+ * **api:** api update ([c0514cb](https://github.com/Finch-API/finch-api-ruby/commit/c0514cb7518217869a5d8dab7771b9e29cf6aa1c))
10
+
11
+
12
+ ### Chores
13
+
14
+ * **internal:** version bump ([a950bdc](https://github.com/Finch-API/finch-api-ruby/commit/a950bdccc42fa2c4fa7bd8297b74be17792cec34))
15
+
16
+ ## 0.1.0-alpha.17 (2025-05-16)
17
+
18
+ Full Changelog: [v0.1.0-alpha.16...v0.1.0-alpha.17](https://github.com/Finch-API/finch-api-ruby/compare/v0.1.0-alpha.16...v0.1.0-alpha.17)
19
+
20
+ ### Features
21
+
22
+ * **api:** api update ([2cd7677](https://github.com/Finch-API/finch-api-ruby/commit/2cd76772fe2768477bb236372c94887a7f1f7022))
23
+ * **api:** api update ([db14723](https://github.com/Finch-API/finch-api-ruby/commit/db147236a70addae46834af9b8339400480a7600))
24
+ * **api:** api update ([1f0346a](https://github.com/Finch-API/finch-api-ruby/commit/1f0346afcca537802e8287a46bc2f759e909975f))
25
+ * bump default connection pool size limit to minimum of 99 ([2e0e107](https://github.com/Finch-API/finch-api-ruby/commit/2e0e1078e5a29ffb965346cd6f620743f0e4b6db))
26
+ * expose base client options as read only attributes ([289fb00](https://github.com/Finch-API/finch-api-ruby/commit/289fb00361821da703dbc9aab1db9ad8435427e3))
27
+ * expose recursive `#to_h` conversion ([03335a6](https://github.com/Finch-API/finch-api-ruby/commit/03335a6a67ce9176fecdafc79c98ddeb22210803))
28
+ * support sorbet aliases at the runtime ([beb18c8](https://github.com/Finch-API/finch-api-ruby/commit/beb18c85b5edba3d056d5d480f9fc4d19ea751a4))
29
+
30
+
31
+ ### Bug Fixes
32
+
33
+ * **internal:** update gemspec name ([70eb621](https://github.com/Finch-API/finch-api-ruby/commit/70eb6214cf238d92f6b2f23969f252a5e4ce3941))
34
+
35
+
36
+ ### Chores
37
+
38
+ * fix misc linting / minor issues ([9c271ed](https://github.com/Finch-API/finch-api-ruby/commit/9c271edf9374973a70e98774d1f55959181ed6be))
39
+ * **internal:** version bump ([f365e16](https://github.com/Finch-API/finch-api-ruby/commit/f365e164984a15deeb545bc07ab8a85373d840ea))
40
+
41
+
42
+ ### Documentation
43
+
44
+ * rewrite much of README.md for readability ([d5fac03](https://github.com/Finch-API/finch-api-ruby/commit/d5fac031d01715a45d40fab30e856e42c601a9a9))
45
+
3
46
  ## 0.1.0-alpha.16 (2025-05-08)
4
47
 
5
48
  Full Changelog: [v0.1.0-alpha.15...v0.1.0-alpha.16](https://github.com/Finch-API/finch-api-ruby/compare/v0.1.0-alpha.15...v0.1.0-alpha.16)
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Finch Ruby API library
2
2
 
3
- The Finch Ruby library provides convenient access to the Finch REST API from any Ruby 3.2.0+ application.
3
+ The Finch Ruby library provides convenient access to the Finch REST API from any Ruby 3.2.0+ application. It ships with comprehensive types & docstrings in Yard, RBS, and RBI – [see below](https://github.com/Finch-API/finch-api-ruby#Sorbet) for usage with Sorbet. The standard library's `net/http` is used as the HTTP transport, with connection pooling via the `connection_pool` gem.
4
4
 
5
5
  It is generated with [Stainless](https://www.stainless.com/).
6
6
 
@@ -17,7 +17,7 @@ To use this gem, install via Bundler by adding the following to your application
17
17
  <!-- x-release-please-start-version -->
18
18
 
19
19
  ```ruby
20
- gem "finch-api", "~> 0.1.0.pre.alpha.16"
20
+ gem "finch-api", "~> 0.1.0.pre.alpha.18"
21
21
  ```
22
22
 
23
23
  <!-- x-release-please-end -->
@@ -35,16 +35,6 @@ page = finch.hris.directory.list
35
35
  puts(page.id)
36
36
  ```
37
37
 
38
- ## Sorbet
39
-
40
- This library is written with [Sorbet type definitions](https://sorbet.org/docs/rbi). However, there is no runtime dependency on the `sorbet-runtime`.
41
-
42
- When using sorbet, it is recommended to use model classes as below. This provides stronger type checking and tooling integration.
43
-
44
- ```ruby
45
- finch.hris.directory.list
46
- ```
47
-
48
38
  ### Pagination
49
39
 
50
40
  List methods in the Finch API are paginated.
@@ -64,15 +54,30 @@ page.auto_paging_each do |directory|
64
54
  end
65
55
  ```
66
56
 
67
- ### Errors
57
+ Alternatively, you can use the `#next_page?` and `#next_page` methods for more granular control working with pages.
58
+
59
+ ```ruby
60
+ if page.next_page?
61
+ new_page = page.next_page
62
+ puts(new_page.individuals[0].id)
63
+ end
64
+ ```
65
+
66
+ ### Handling errors
68
67
 
69
68
  When the library is unable to connect to the API, or if the API returns a non-success status code (i.e., 4xx or 5xx response), a subclass of `FinchAPI::Errors::APIError` will be thrown:
70
69
 
71
70
  ```ruby
72
71
  begin
73
72
  company = finch.hris.company.retrieve
74
- rescue FinchAPI::Errors::APIError => e
75
- puts(e.status) # 400
73
+ rescue FinchAPI::Errors::APIConnectionError => e
74
+ puts("The server could not be reached")
75
+ puts(e.cause) # an underlying Exception, likely raised within `net/http`
76
+ rescue FinchAPI::Errors::RateLimitError => e
77
+ puts("A 429 status code was received; we should back off a bit.")
78
+ rescue FinchAPI::Errors::APIStatusError => e
79
+ puts("Another non-200-range status code was received")
80
+ puts(e.status)
76
81
  end
77
82
  ```
78
83
 
@@ -112,11 +117,7 @@ finch.hris.directory.list(request_options: {max_retries: 5})
112
117
 
113
118
  ### Timeouts
114
119
 
115
- By default, requests will time out after 60 seconds.
116
-
117
- Timeouts are applied separately to the initial connection and the overall request time, so in some cases a request could wait 2\*timeout seconds before it fails.
118
-
119
- You can use the `timeout` option to configure or disable this:
120
+ By default, requests will time out after 60 seconds. You can use the timeout option to configure or disable this:
120
121
 
121
122
  ```ruby
122
123
  # Configure the default for all requests:
@@ -128,39 +129,52 @@ finch = FinchAPI::Client.new(
128
129
  finch.hris.directory.list(request_options: {timeout: 5})
129
130
  ```
130
131
 
131
- ## Model DSL
132
+ On timeout, `FinchAPI::Errors::APITimeoutError` is raised.
133
+
134
+ Note that requests that time out are retried by default.
132
135
 
133
- This library uses a simple DSL to represent request parameters and response shapes in `lib/finch_api/models`.
136
+ ## Advanced concepts
134
137
 
135
- With the right [editor plugins](https://shopify.github.io/ruby-lsp), you can ctrl-click on elements of the DSL to navigate around and explore the library.
138
+ ### BaseModel
136
139
 
137
- In all places where a `BaseModel` type is specified, vanilla Ruby `Hash` can also be used. For example, the following are interchangeable as arguments:
140
+ All parameter and response objects inherit from `FinchAPI::Internal::Type::BaseModel`, which provides several conveniences, including:
138
141
 
139
- ```ruby
140
- # This has tooling readability, for auto-completion, static analysis, and goto definition with supported language services
141
- params = FinchAPI::Models::HRIS::DirectoryListParams.new
142
+ 1. All fields, including unknown ones, are accessible with `obj[:prop]` syntax, and can be destructured with `obj => {prop: prop}` or pattern-matching syntax.
142
143
 
143
- # This also works
144
- params = {
144
+ 2. Structural equivalence for equality; if two API calls return the same values, comparing the responses with == will return true.
145
145
 
146
- }
147
- ```
146
+ 3. Both instances and the classes themselves can be pretty-printed.
148
147
 
149
- ## Editor support
148
+ 4. Helpers such as `#to_h`, `#deep_to_h`, `#to_json`, and `#to_yaml`.
150
149
 
151
- A combination of [Shopify LSP](https://shopify.github.io/ruby-lsp) and [Solargraph](https://solargraph.org/) is recommended for non-[Sorbet](https://sorbet.org) users. The former is especially good at go to definition, while the latter has much better auto-completion support.
150
+ ### Making custom or undocumented requests
152
151
 
153
- ## Advanced concepts
152
+ #### Undocumented properties
153
+
154
+ You can send undocumented parameters to any endpoint, and read undocumented response properties, like so:
154
155
 
155
- ### Making custom/undocumented requests
156
+ Note: the `extra_` parameters of the same name overrides the documented parameters.
157
+
158
+ ```ruby
159
+ page =
160
+ finch.hris.directory.list(
161
+ request_options: {
162
+ extra_query: {my_query_parameter: value},
163
+ extra_body: {my_body_parameter: value},
164
+ extra_headers: {"my-header": value}
165
+ }
166
+ )
167
+
168
+ puts(page[:my_undocumented_property])
169
+ ```
156
170
 
157
171
  #### Undocumented request params
158
172
 
159
- If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` under the `request_options:` parameter when making a requests as seen in examples above.
173
+ If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` under the `request_options:` parameter when making a request as seen in examples above.
160
174
 
161
175
  #### Undocumented endpoints
162
176
 
163
- To make requests to undocumented endpoints, you can make requests using `client.request`. Options on the client will be respected (such as retries) when making this request.
177
+ To make requests to undocumented endpoints while retaining the benefit of auth, retries, and so on, you can make requests using `client.request`, like so:
164
178
 
165
179
  ```ruby
166
180
  response = client.request(
@@ -168,42 +182,67 @@ response = client.request(
168
182
  path: '/undocumented/endpoint',
169
183
  query: {"dog": "woof"},
170
184
  headers: {"useful-header": "interesting-value"},
171
- body: {"he": "llo"},
185
+ body: {"hello": "world"}
172
186
  )
173
187
  ```
174
188
 
175
189
  ### Concurrency & connection pooling
176
190
 
177
- The `FinchAPI::Client` instances are thread-safe, and should be re-used across multiple threads. By default, each `Client` have their own HTTP connection pool, with a maximum number of connections equal to thread count.
191
+ The `FinchAPI::Client` instances are threadsafe, but only are fork-safe when there are no in-flight HTTP requests.
178
192
 
179
- When the maximum number of connections has been checked out from the connection pool, the `Client` will wait for an in use connection to become available. The queue time for this mechanism is accounted for by the per-request timeout.
193
+ Each instance of `FinchAPI::Client` has its own HTTP connection pool with a default size of 99. As such, we recommend instantiating the client once per application in most settings.
194
+
195
+ When all available connections from the pool are checked out, requests wait for a new connection to become available, with queue time counting towards the request timeout.
180
196
 
181
197
  Unless otherwise specified, other classes in the SDK do not have locks protecting their underlying data structure.
182
198
 
183
- Currently, `FinchAPI::Client` instances are only fork-safe if there are no in-flight HTTP requests.
199
+ ## Sorbet
184
200
 
185
- ### Sorbet
201
+ This library provides comprehensive [RBI](https://sorbet.org/docs/rbi) definitions, and has no dependency on sorbet-runtime.
186
202
 
187
- #### Enums
203
+ You can provide typesafe request parameters like so:
188
204
 
189
- Sorbet's typed enums require sub-classing of the [`T::Enum` class](https://sorbet.org/docs/tenum) from the `sorbet-runtime` gem.
205
+ ```ruby
206
+ finch.hris.directory.list
207
+ ```
190
208
 
191
- Since this library does not depend on `sorbet-runtime`, it uses a [`T.all` intersection type](https://sorbet.org/docs/intersection-types) with a ruby primitive type to construct a "tagged alias" instead.
209
+ Or, equivalently:
192
210
 
193
211
  ```ruby
194
- module FinchAPI::ConnectionStatusType
195
- # This alias aids language service driven navigation.
196
- TaggedSymbol = T.type_alias { T.all(Symbol, FinchAPI::ConnectionStatusType) }
197
- end
212
+ # Hashes work, but are not typesafe:
213
+ finch.hris.directory.list
214
+
215
+ # You can also splat a full Params class:
216
+ params = FinchAPI::HRIS::DirectoryListParams.new
217
+ finch.hris.directory.list(**params)
198
218
  ```
199
219
 
200
- #### Argument passing trick
220
+ ### Enums
201
221
 
202
- It is possible to pass a compatible model / parameter class to a method that expects keyword arguments by using the `**` splat operator.
222
+ Since this library does not depend on `sorbet-runtime`, it cannot provide [`T::Enum`](https://sorbet.org/docs/tenum) instances. Instead, we provide "tagged symbols" instead, which is always a primitive at runtime:
203
223
 
204
224
  ```ruby
205
- params = FinchAPI::Models::HRIS::DirectoryListParams.new
206
- finch.hris.directory.list(**params)
225
+ # :one_time
226
+ puts(FinchAPI::HRIS::BenefitFrequency::ONE_TIME)
227
+
228
+ # Revealed type: `T.all(FinchAPI::HRIS::BenefitFrequency, Symbol)`
229
+ T.reveal_type(FinchAPI::HRIS::BenefitFrequency::ONE_TIME)
230
+ ```
231
+
232
+ Enum parameters have a "relaxed" type, so you can either pass in enum constants or their literal value:
233
+
234
+ ```ruby
235
+ # Using the enum constants preserves the tagged type information:
236
+ finch.hris.benefits.create(
237
+ frequency: FinchAPI::HRIS::BenefitFrequency::ONE_TIME,
238
+ # …
239
+ )
240
+
241
+ # Literal values is also permissible:
242
+ finch.hris.benefits.create(
243
+ frequency: :one_time,
244
+ # …
245
+ )
207
246
  ```
208
247
 
209
248
  ## Versioning
@@ -103,10 +103,10 @@ module FinchAPI
103
103
  client_secret: ENV["FINCH_CLIENT_SECRET"],
104
104
  access_token: nil,
105
105
  base_url: ENV["FINCH_BASE_URL"],
106
- max_retries: FinchAPI::Client::DEFAULT_MAX_RETRIES,
107
- timeout: FinchAPI::Client::DEFAULT_TIMEOUT_IN_SECONDS,
108
- initial_retry_delay: FinchAPI::Client::DEFAULT_INITIAL_RETRY_DELAY,
109
- max_retry_delay: FinchAPI::Client::DEFAULT_MAX_RETRY_DELAY
106
+ max_retries: self.class::DEFAULT_MAX_RETRIES,
107
+ timeout: self.class::DEFAULT_TIMEOUT_IN_SECONDS,
108
+ initial_retry_delay: self.class::DEFAULT_INITIAL_RETRY_DELAY,
109
+ max_retry_delay: self.class::DEFAULT_MAX_RETRY_DELAY
110
110
  )
111
111
  base_url ||= "https://api.tryfinch.com"
112
112
 
@@ -99,7 +99,7 @@ module FinchAPI
99
99
  # @param response [nil]
100
100
  # @param message [String, nil]
101
101
  #
102
- # @return [FinchAPI::Errors::APIStatusError]
102
+ # @return [self]
103
103
  def self.for(url:, status:, body:, request:, response:, message: nil)
104
104
  kwargs = {
105
105
  url: url,
@@ -7,6 +7,8 @@ module FinchAPI
7
7
  #
8
8
  # @abstract
9
9
  class BaseClient
10
+ extend FinchAPI::Internal::Util::SorbetRuntimeSupport
11
+
10
12
  # from whatwg fetch spec
11
13
  MAX_REDIRECTS = 20
12
14
 
@@ -151,6 +153,27 @@ module FinchAPI
151
153
  end
152
154
  end
153
155
 
156
+ # @return [URI::Generic]
157
+ attr_reader :base_url
158
+
159
+ # @return [Float]
160
+ attr_reader :timeout
161
+
162
+ # @return [Integer]
163
+ attr_reader :max_retries
164
+
165
+ # @return [Float]
166
+ attr_reader :initial_retry_delay
167
+
168
+ # @return [Float]
169
+ attr_reader :max_retry_delay
170
+
171
+ # @return [Hash{String=>String}]
172
+ attr_reader :headers
173
+
174
+ # @return [String, nil]
175
+ attr_reader :idempotency_header
176
+
154
177
  # @api private
155
178
  # @return [FinchAPI::Internal::Transport::PooledNetRequester]
156
179
  attr_reader :requester
@@ -182,10 +205,11 @@ module FinchAPI
182
205
  },
183
206
  headers
184
207
  )
185
- @base_url = FinchAPI::Internal::Util.parse_uri(base_url)
208
+ @base_url_components = FinchAPI::Internal::Util.parse_uri(base_url)
209
+ @base_url = FinchAPI::Internal::Util.unparse_uri(@base_url_components)
186
210
  @idempotency_header = idempotency_header&.to_s&.downcase
187
- @max_retries = max_retries
188
211
  @timeout = timeout
212
+ @max_retries = max_retries
189
213
  @initial_retry_delay = initial_retry_delay
190
214
  @max_retry_delay = max_retry_delay
191
215
  end
@@ -276,10 +300,14 @@ module FinchAPI
276
300
  FinchAPI::Internal::Util.deep_merge(*[req[:body], opts[:extra_body]].compact)
277
301
  end
278
302
 
303
+ url = FinchAPI::Internal::Util.join_parsed_uri(
304
+ @base_url_components,
305
+ {**req, path: path, query: query}
306
+ )
279
307
  headers, encoded = FinchAPI::Internal::Util.encode_content(headers, body)
280
308
  {
281
309
  method: method,
282
- url: FinchAPI::Internal::Util.join_parsed_uri(@base_url, {**req, path: path, query: query}),
310
+ url: url,
283
311
  headers: headers,
284
312
  body: encoded,
285
313
  max_retries: opts.fetch(:max_retries, @max_retries),
@@ -473,10 +501,54 @@ module FinchAPI
473
501
  # @return [String]
474
502
  def inspect
475
503
  # rubocop:disable Layout/LineLength
476
- base_url = FinchAPI::Internal::Util.unparse_uri(@base_url)
477
- "#<#{self.class.name}:0x#{object_id.to_s(16)} base_url=#{base_url} max_retries=#{@max_retries} timeout=#{@timeout}>"
504
+ "#<#{self.class.name}:0x#{object_id.to_s(16)} base_url=#{@base_url} max_retries=#{@max_retries} timeout=#{@timeout}>"
478
505
  # rubocop:enable Layout/LineLength
479
506
  end
507
+
508
+ define_sorbet_constant!(:RequestComponents) do
509
+ T.type_alias do
510
+ {
511
+ method: Symbol,
512
+ path: T.any(String, T::Array[String]),
513
+ query: T.nilable(T::Hash[String, T.nilable(T.any(T::Array[String], String))]),
514
+ headers: T.nilable(
515
+ T::Hash[String,
516
+ T.nilable(
517
+ T.any(
518
+ String,
519
+ Integer,
520
+ T::Array[T.nilable(T.any(String, Integer))]
521
+ )
522
+ )]
523
+ ),
524
+ body: T.nilable(T.anything),
525
+ unwrap: T.nilable(
526
+ T.any(
527
+ Symbol,
528
+ Integer,
529
+ T::Array[T.any(Symbol, Integer)],
530
+ T.proc.params(arg0: T.anything).returns(T.anything)
531
+ )
532
+ ),
533
+ page: T.nilable(T::Class[FinchAPI::Internal::Type::BasePage[FinchAPI::Internal::Type::BaseModel]]),
534
+ stream: T.nilable(T::Class[T.anything]),
535
+ model: T.nilable(FinchAPI::Internal::Type::Converter::Input),
536
+ options: T.nilable(FinchAPI::RequestOptions::OrHash)
537
+ }
538
+ end
539
+ end
540
+ define_sorbet_constant!(:RequestInput) do
541
+ T.type_alias do
542
+ {
543
+ method: Symbol,
544
+ url: URI::Generic,
545
+ headers: T::Hash[String, String],
546
+ body: T.anything,
547
+ max_retries: Integer,
548
+ timeout: Float
549
+ }
550
+ end
551
+ end
480
552
  end
481
553
  end
482
554
  end
@@ -5,10 +5,14 @@ module FinchAPI
5
5
  module Transport
6
6
  # @api private
7
7
  class PooledNetRequester
8
+ extend FinchAPI::Internal::Util::SorbetRuntimeSupport
9
+
8
10
  # from the golang stdlib
9
11
  # https://github.com/golang/go/blob/c8eced8580028328fde7c03cbfcb720ce15b2358/src/net/http/transport.go#L49
10
12
  KEEP_ALIVE_TIMEOUT = 30
11
13
 
14
+ DEFAULT_MAX_CONNECTIONS = [Etc.nprocessors, 99].max
15
+
12
16
  class << self
13
17
  # @api private
14
18
  #
@@ -182,11 +186,23 @@ module FinchAPI
182
186
  # @api private
183
187
  #
184
188
  # @param size [Integer]
185
- def initialize(size: Etc.nprocessors)
189
+ def initialize(size: self.class::DEFAULT_MAX_CONNECTIONS)
186
190
  @mutex = Mutex.new
187
191
  @size = size
188
192
  @pools = {}
189
193
  end
194
+
195
+ define_sorbet_constant!(:Request) do
196
+ T.type_alias do
197
+ {
198
+ method: Symbol,
199
+ url: URI::Generic,
200
+ headers: T::Hash[String, String],
201
+ body: T.anything,
202
+ deadline: Float
203
+ }
204
+ end
205
+ end
190
206
  end
191
207
  end
192
208
  end
@@ -29,7 +29,7 @@ module FinchAPI
29
29
  #
30
30
  # @option spec [Boolean] :"nil?"
31
31
  #
32
- # @return [FinchAPI::Internal::Type::ArrayOf]
32
+ # @return [self]
33
33
  def self.[](...) = new(...)
34
34
 
35
35
  # @api public
@@ -6,6 +6,7 @@ module FinchAPI
6
6
  # @abstract
7
7
  class BaseModel
8
8
  extend FinchAPI::Internal::Type::Converter
9
+ extend FinchAPI::Internal::Util::SorbetRuntimeSupport
9
10
 
10
11
  class << self
11
12
  # @api private
@@ -13,11 +14,17 @@ module FinchAPI
13
14
  # Assumes superclass fields are totally defined before fields are accessed /
14
15
  # defined on subclasses.
15
16
  #
16
- # @return [Hash{Symbol=>Hash{Symbol=>Object}}]
17
- def known_fields
18
- @known_fields ||= (self < FinchAPI::Internal::Type::BaseModel ? superclass.known_fields.dup : {})
17
+ # @param child [Class<FinchAPI::Internal::Type::BaseModel>]
18
+ def inherited(child)
19
+ super
20
+ child.known_fields.replace(known_fields.dup)
19
21
  end
20
22
 
23
+ # @api private
24
+ #
25
+ # @return [Hash{Symbol=>Hash{Symbol=>Object}}]
26
+ def known_fields = @known_fields ||= {}
27
+
21
28
  # @api private
22
29
  #
23
30
  # @return [Hash{Symbol=>Hash{Symbol=>Object}}]
@@ -206,7 +213,7 @@ module FinchAPI
206
213
  #
207
214
  # @option state [Integer] :branched
208
215
  #
209
- # @return [FinchAPI::Internal::Type::BaseModel, Object]
216
+ # @return [self, Object]
210
217
  def coerce(value, state:)
211
218
  exactness = state.fetch(:exactness)
212
219
 
@@ -265,7 +272,7 @@ module FinchAPI
265
272
 
266
273
  # @api private
267
274
  #
268
- # @param value [FinchAPI::Internal::Type::BaseModel, Object]
275
+ # @param value [self, Object]
269
276
  #
270
277
  # @param state [Hash{Symbol=>Object}] .
271
278
  #
@@ -306,6 +313,39 @@ module FinchAPI
306
313
  end
307
314
  end
308
315
 
316
+ class << self
317
+ # @api private
318
+ #
319
+ # @param model [FinchAPI::Internal::Type::BaseModel]
320
+ # @param convert [Boolean]
321
+ #
322
+ # @return [Hash{Symbol=>Object}]
323
+ def recursively_to_h(model, convert:)
324
+ rec = ->(x) do
325
+ case x
326
+ in FinchAPI::Internal::Type::BaseModel
327
+ if convert
328
+ fields = x.class.known_fields
329
+ x.to_h.to_h do |key, val|
330
+ [key, rec.call(fields.key?(key) ? x.public_send(key) : val)]
331
+ rescue FinchAPI::Errors::ConversionError
332
+ [key, rec.call(val)]
333
+ end
334
+ else
335
+ rec.call(x.to_h)
336
+ end
337
+ in Hash
338
+ x.transform_values(&rec)
339
+ in Array
340
+ x.map(&rec)
341
+ else
342
+ x
343
+ end
344
+ end
345
+ rec.call(model)
346
+ end
347
+ end
348
+
309
349
  # @api public
310
350
  #
311
351
  # Returns the raw value associated with the given key, if found. Otherwise, nil is
@@ -342,9 +382,25 @@ module FinchAPI
342
382
 
343
383
  alias_method :to_hash, :to_h
344
384
 
385
+ # @api public
386
+ #
387
+ # In addition to the behaviour of `#to_h`, this method will recursively call
388
+ # `#to_h` on nested models.
389
+ #
390
+ # @return [Hash{Symbol=>Object}]
391
+ def deep_to_h = self.class.recursively_to_h(@data, convert: false)
392
+
345
393
  # @param keys [Array<Symbol>, nil]
346
394
  #
347
395
  # @return [Hash{Symbol=>Object}]
396
+ #
397
+ # @example
398
+ # # `operation_support_matrix` is a `FinchAPI::OperationSupportMatrix`
399
+ # operation_support_matrix => {
400
+ # create: create,
401
+ # delete: delete,
402
+ # read: read
403
+ # }
348
404
  def deconstruct_keys(keys)
349
405
  (keys || self.class.known_fields.keys)
350
406
  .filter_map do |k|
@@ -357,29 +413,6 @@ module FinchAPI
357
413
  .to_h
358
414
  end
359
415
 
360
- class << self
361
- # @api private
362
- #
363
- # @param model [FinchAPI::Internal::Type::BaseModel]
364
- #
365
- # @return [Hash{Symbol=>Object}]
366
- def walk(model)
367
- walk = ->(x) do
368
- case x
369
- in FinchAPI::Internal::Type::BaseModel
370
- walk.call(x.to_h)
371
- in Hash
372
- x.transform_values(&walk)
373
- in Array
374
- x.map(&walk)
375
- else
376
- x
377
- end
378
- end
379
- walk.call(model)
380
- end
381
- end
382
-
383
416
  # @api public
384
417
  #
385
418
  # @param a [Object]
@@ -425,12 +458,19 @@ module FinchAPI
425
458
  # @api public
426
459
  #
427
460
  # @return [String]
428
- def to_s = self.class.walk(@data).to_s
461
+ def to_s = deep_to_h.to_s
429
462
 
430
463
  # @api private
431
464
  #
432
465
  # @return [String]
433
- def inspect = "#<#{self.class}:0x#{object_id.to_s(16)} #{self}>"
466
+ def inspect
467
+ converted = self.class.recursively_to_h(self, convert: true)
468
+ "#<#{self.class}:0x#{object_id.to_s(16)} #{converted}>"
469
+ end
470
+
471
+ define_sorbet_constant!(:KnownField) do
472
+ T.type_alias { {mode: T.nilable(Symbol), required: T::Boolean, nilable: T::Boolean} }
473
+ end
434
474
  end
435
475
  end
436
476
  end