recurly 3.0.0.beta.5 → 3.0.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 +5 -5
- data/.bumpversion.cfg +12 -0
- data/.travis.yml +2 -2
- data/.yardopts +3 -0
- data/CONTRIBUTING.md +102 -0
- data/GETTING_STARTED.md +266 -0
- data/README.md +12 -194
- data/benchmark.rb +16 -0
- data/lib/recurly.rb +4 -7
- data/lib/recurly/client.rb +60 -60
- data/lib/recurly/client/operations.rb +498 -340
- data/lib/recurly/errors.rb +4 -0
- data/lib/recurly/http.rb +43 -0
- data/lib/recurly/pager.rb +4 -10
- data/lib/recurly/request.rb +6 -6
- data/lib/recurly/requests.rb +8 -0
- data/lib/recurly/requests/account_acquisition_updatable.rb +2 -2
- data/lib/recurly/requests/billing_info_create.rb +4 -0
- data/lib/recurly/requests/custom_field.rb +18 -0
- data/lib/recurly/requests/invoice_create.rb +0 -4
- data/lib/recurly/requests/invoice_refund.rb +2 -2
- data/lib/recurly/requests/line_item_create.rb +4 -0
- data/lib/recurly/requests/purchase_create.rb +3 -7
- data/lib/recurly/requests/shipping_fee_create.rb +22 -0
- data/lib/recurly/requests/shipping_purchase.rb +22 -0
- data/lib/recurly/requests/subscription_add_on_create.rb +2 -6
- data/lib/recurly/requests/subscription_add_on_update.rb +26 -0
- data/lib/recurly/requests/subscription_change_create.rb +7 -3
- data/lib/recurly/requests/subscription_change_shipping_create.rb +22 -0
- data/lib/recurly/requests/subscription_create.rb +4 -8
- data/lib/recurly/requests/subscription_shipping_create.rb +30 -0
- data/lib/recurly/requests/subscription_shipping_update.rb +22 -0
- data/lib/recurly/requests/subscription_update.rb +3 -7
- data/lib/recurly/resource.rb +14 -1
- data/lib/recurly/resources.rb +17 -0
- data/lib/recurly/resources/account_acquisition.rb +2 -2
- data/lib/recurly/resources/add_on.rb +1 -1
- data/lib/recurly/resources/billing_info.rb +6 -6
- data/lib/recurly/resources/coupon.rb +1 -1
- data/lib/recurly/resources/coupon_discount.rb +2 -2
- data/lib/recurly/resources/coupon_redemption.rb +2 -2
- data/lib/recurly/resources/coupon_redemption_mini.rb +2 -2
- data/lib/recurly/resources/error_may_have_transaction.rb +2 -2
- data/lib/recurly/resources/invoice.rb +4 -0
- data/lib/recurly/resources/line_item.rb +1 -1
- data/lib/recurly/resources/{billing_info_payment_method.rb → payment_method.rb} +18 -2
- data/lib/recurly/resources/plan.rb +1 -1
- data/lib/recurly/resources/shipping_method.rb +42 -0
- data/lib/recurly/resources/shipping_method_mini.rb +26 -0
- data/lib/recurly/resources/subscription.rb +3 -3
- data/lib/recurly/resources/subscription_change.rb +4 -0
- data/lib/recurly/resources/subscription_shipping.rb +26 -0
- data/lib/recurly/resources/transaction.rb +4 -4
- data/lib/recurly/resources/transaction_error.rb +30 -0
- data/lib/recurly/schema.rb +85 -49
- data/lib/recurly/schema/json_parser.rb +16 -8
- data/lib/recurly/schema/request_caster.rb +10 -16
- data/lib/recurly/schema/resource_caster.rb +48 -0
- data/lib/recurly/schema/schema_factory.rb +0 -2
- data/lib/recurly/schema/schema_validator.rb +11 -14
- data/lib/recurly/version.rb +1 -1
- data/recurly.gemspec +6 -6
- data/scripts/build +1 -0
- data/scripts/bump +4 -0
- data/scripts/format +2 -0
- data/scripts/release +11 -0
- data/scripts/test +1 -0
- metadata +38 -20
- data/.ruby-version +0 -1
- data/lib/recurly/resources/transaction_payment_method.rb +0 -34
- data/lib/recurly/schema/json_deserializer.rb +0 -56
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 22a128d84f15a6887446e5f7791f3d6b91d67cec94641198ff3a4317c73a17a5
|
4
|
+
data.tar.gz: 71ac80f190a092f50cc8e9b2f7d8ab9eb5a91aa0528cacccbce642e488ef9616
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba861fa4d8f40dcc52e3cd4f2b7484aeaf90d5364deaccdf4e9e5894ee15cfdf98c3f05042d7916dd492278244a986fdfb547837214354eab3fc6c1678eb168b
|
7
|
+
data.tar.gz: bf1733bd81f4250afa91841f1e352bb884378c4edfb47bab62857c18d0ba40c74d7e1fdebbdacfc2a4289c31a895c675427d181688840e71a7da5e14a1997b01
|
data/.bumpversion.cfg
ADDED
data/.travis.yml
CHANGED
data/.yardopts
ADDED
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# Contributing Guide
|
2
|
+
|
3
|
+
👍🎉 First off, thanks for taking the time to contribute! 🎉👍
|
4
|
+
|
5
|
+
Filing an Issue or a Pull Request is often the best way to address a problem with this library;
|
6
|
+
however, we may not get to these right away. Although we try to be quick, our primary, daily focus is
|
7
|
+
writing code. If you want a timely response (especially if you have an emergency), we recommend
|
8
|
+
you contact our [official support team](https://support.recurly.com/).
|
9
|
+
|
10
|
+
#### Table Of Contents
|
11
|
+
|
12
|
+
* [I don't want to read this whole thing, I just have a question!!!](#i-dont-want-to-read-this-whole-thing-i-just-have-a-question)
|
13
|
+
* [I think something is wrong with this library](#i-think-something-is-wrong-with-this-library)
|
14
|
+
* [I know what's wrong and I want to submit a code change](#i-know-whats-wrong-and-i-want-to-submit-a-code-change)
|
15
|
+
* [Development Dependencies](#development-dependencies)
|
16
|
+
* [Building and Testing](#building-and-testing)
|
17
|
+
* [Formatting Code](#formatting-code)
|
18
|
+
* [Generated Code](#generated-code)
|
19
|
+
|
20
|
+
|
21
|
+
## I don't want to read this whole thing I just have a question!!!
|
22
|
+
|
23
|
+
The best way to get a question answered is through our [official support channel](https://support.recurly.com/). If you
|
24
|
+
have a specific question related to this library and cannot find an answer, feel free to post an issue with the question.
|
25
|
+
|
26
|
+
## I think something is wrong with this library
|
27
|
+
|
28
|
+
Are you getting an exception or seeing some unexpected behavior from the library? An issue is the way to go.
|
29
|
+
Submit an issue and make sure you provide as much detail as possible. Some things you'll want to include:
|
30
|
+
|
31
|
+
* Your dependency versions (client version, language version, OS, etc)
|
32
|
+
* A stack trace if available
|
33
|
+
* A [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example)
|
34
|
+
|
35
|
+
The more information you give us, the quicker and easier the response will be. Keep in mind that issues should be scoped
|
36
|
+
to a problem in this library and we may often redirect you to our official support for problems originating from
|
37
|
+
upstream systems.
|
38
|
+
|
39
|
+
## I know what's wrong and I want to submit a code change
|
40
|
+
|
41
|
+
So, you are sure you want to submit a change to the code? We appreciate the help!
|
42
|
+
Before you do, consider opening a discussion in the form of an issue. This accomplish a few things:
|
43
|
+
|
44
|
+
1. We can give you advice to implement the change
|
45
|
+
2. We can give you an idea of our openness to the change
|
46
|
+
|
47
|
+
**Note**: Sending code without a discussion is *always* fine. Discussion on the PR is often easier anyway. Just understand that we may
|
48
|
+
not accept the code if we don't think it's best for everyone using the library.
|
49
|
+
|
50
|
+
The rest of this section describes what you'll need to know.
|
51
|
+
|
52
|
+
### Development Dependencies
|
53
|
+
|
54
|
+
You're going to first need a supported version of the language toolchain. The best way to find which versions are supported are by checking
|
55
|
+
the [Travis File](.travis.yml) which is used to run our tests. We try to test against every supported version of the language. The [README](README.md)
|
56
|
+
may also have something to say about supported dependencies.
|
57
|
+
|
58
|
+
### Building and Testing
|
59
|
+
|
60
|
+
All of our client libraries contain a `scripts` folder which houses a set of bash scripts for doing common
|
61
|
+
development tasks. These scripts follow the same naming conventions so this can act as a kind of "Bash API"
|
62
|
+
for manipulating the libraries.
|
63
|
+
|
64
|
+
**Note**: If you are on a system without bash (such as some Windows systems), you should find the scripts only consist of a
|
65
|
+
few commands which can easily be run in your terminal or editor directly.
|
66
|
+
|
67
|
+
Start by running the `build` script to setup deps, compile (if applicable), build docs, etc:
|
68
|
+
|
69
|
+
```bash
|
70
|
+
./scripts/build
|
71
|
+
```
|
72
|
+
|
73
|
+
Use the `test` script to run the tests:
|
74
|
+
|
75
|
+
```bash
|
76
|
+
./scripts/test
|
77
|
+
```
|
78
|
+
|
79
|
+
Make sure the tests pass locally before submitting your change.
|
80
|
+
|
81
|
+
### Formatting Code
|
82
|
+
|
83
|
+
The PR (and often the tests) will fail if you have not properly formatted the code. Instead of having a style-guide, we've provided
|
84
|
+
an auto-formatter. To use it, run the `format` script:
|
85
|
+
|
86
|
+
```bash
|
87
|
+
./scripts/format
|
88
|
+
```
|
89
|
+
|
90
|
+
### Generated Code
|
91
|
+
|
92
|
+
Some files in this codebase are generated by a non-public, proprietary program. Because they are regularly generated and updated as the
|
93
|
+
API and docs change, we won't accept any PRs that modify these files. Each of these files has a disclaimer on the top saying that they cannot
|
94
|
+
be edited by hand. By convention, they relate to things that are specific to the Recurly API that may change. For example:
|
95
|
+
|
96
|
+
* Response Schemas (Resources)
|
97
|
+
* Request Schemas (Requests)
|
98
|
+
* API endpoints (Operations)
|
99
|
+
* Errors
|
100
|
+
|
101
|
+
If you feel like you need one of these to change, please file an issue and we can discuss getting the change upstreamed.
|
102
|
+
|
data/GETTING_STARTED.md
ADDED
@@ -0,0 +1,266 @@
|
|
1
|
+
# Recurly
|
2
|
+
|
3
|
+
## Getting Started
|
4
|
+
|
5
|
+
### Installing
|
6
|
+
|
7
|
+
In your Gemfile, add `recurly` as a dependency.
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'recurly', '~> 3.0'
|
11
|
+
```
|
12
|
+
|
13
|
+
> *Note*: We try to follow [semantic versioning](https://semver.org/) and will only apply breaking changes to major versions.
|
14
|
+
|
15
|
+
### Creating a client
|
16
|
+
|
17
|
+
Client instances are now explicitly created and referenced as opposed to V2's use of global, statically
|
18
|
+
initialized clients.
|
19
|
+
|
20
|
+
This makes multithreaded environments simpler and provides one location where every
|
21
|
+
operation can be found (rather than having them spread out among classes).
|
22
|
+
|
23
|
+
`Recurly::Client#new` initializes a new client. It only requires an API key which can be obtained on
|
24
|
+
the [API Credentials Page](https://app.recurly.com/go/integrations/api_keys).
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
API_KEY = '83749879bbde395b5fe0cc1a5abf8e5'
|
28
|
+
client = Recurly::Client.new(api_key: API_KEY)
|
29
|
+
sub = client.get_subscription(subscription_id: 'abcd123456')
|
30
|
+
```
|
31
|
+
|
32
|
+
You can also pass the initializer a block. This will give you a client scoped for just that block:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
Recurly::Client.new(api_key: API_KEY) do |client|
|
36
|
+
sub = client.get_subscription(subscription_id: 'abcd123456')
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
If you plan on using the client for more than one site, you should initialize a new client for each site.
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
client = Recurly::Client.new(api_key: API_KEY1)
|
44
|
+
sub = client.get_subscription(subscription_id: 'abcd123456')
|
45
|
+
|
46
|
+
# you should create a new client to connect to another site
|
47
|
+
client = Recurly::Client.new(api_key: API_KEY2)
|
48
|
+
sub = client.get_subscription(subscription_id: 'abcd7890')
|
49
|
+
```
|
50
|
+
|
51
|
+
### Operations
|
52
|
+
|
53
|
+
The {Recurly::Client} contains every `operation` you can perform on the site as a list of methods. Each method is documented explaining
|
54
|
+
the types and descriptions for each input and return type. You can view all available operations by looking at the `Instance Methods Summary` list
|
55
|
+
on the {Recurly::Client} documentation page. Clicking a method will give you detailed information about its inputs and returns. Take the `create_account`
|
56
|
+
operation as an example: {Recurly::Client#create_account}.
|
57
|
+
|
58
|
+
### Pagination
|
59
|
+
|
60
|
+
Pagination is done by the class {Recurly::Pager}. All `list_*` methods on the client return an instance of this class.
|
61
|
+
The pager has an `each` method which accepts a block for each object in the entire list. Each page is fetched automatically
|
62
|
+
for you presenting the elements as a single enumerable.
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
plans = client.list_plans()
|
66
|
+
plans.each do |plan|
|
67
|
+
puts "Plan: #{plan.id}"
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
You may also paginate in chunks with `each_page`.
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
plans = client.list_plans()
|
75
|
+
plans.each_page do |data|
|
76
|
+
data.each do |plan|
|
77
|
+
puts "Plan: #{plan.id}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
Both {Pager#each} and {Pager#each_page} return Enumerators if a block is not given. This allows you to use other Enumerator methods
|
83
|
+
such as `map` or `each_with_index`.
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
plans = client.list_plans()
|
87
|
+
plans.each_page.each_with_index do |data, page_num|
|
88
|
+
puts "Page Number #{page_num}"
|
89
|
+
data.each do |plan|
|
90
|
+
puts "Plan: #{plan.id}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
```
|
94
|
+
|
95
|
+
Pagination endpoints take a number of options to sort and filter the results. They can be passed in as keyword arguments.
|
96
|
+
The names, types, and descriptions of these arguments are listed in the rubydocs for each method:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
options = {
|
100
|
+
limit: 200, # number of items per page
|
101
|
+
state: :active, # only active plans
|
102
|
+
sort: :updated_at,
|
103
|
+
order: :asc,
|
104
|
+
begin_time: DateTime.new(2017,1,1), # January 1st 2017,
|
105
|
+
end_time: DateTime.now
|
106
|
+
}
|
107
|
+
|
108
|
+
plans = client.list_plans(**options)
|
109
|
+
plans.each do |plan|
|
110
|
+
puts "Plan: #{plan.id}"
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
**A note on `limit`**:
|
115
|
+
|
116
|
+
`limit` defaults to 20 items per page and can be set from 1 to 200. Choosing a lower limit means more network requests but smaller payloads.
|
117
|
+
We recommend keeping the default for most cases but increasing the limit if you are planning on iterating through many pages of items (e.g. all transactions in your site).
|
118
|
+
|
119
|
+
|
120
|
+
### Creating Resources
|
121
|
+
|
122
|
+
Currently, resources are created by passing in a `body` keyword argument in the form of a `Hash`.
|
123
|
+
This Hash must follow the schema of the documented request type. For example, the `create_plan` operation
|
124
|
+
takes a request of type {Recurly::Requests::PlanCreate}. Failing to conform to this schema will result in an argument
|
125
|
+
error.
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
require 'securerandom'
|
129
|
+
|
130
|
+
code = SecureRandom.uuid
|
131
|
+
plan_data = {
|
132
|
+
code: code,
|
133
|
+
interval_length: 1,
|
134
|
+
interval_unit: 'months',
|
135
|
+
name: code,
|
136
|
+
currencies: [
|
137
|
+
{
|
138
|
+
currency: 'USD',
|
139
|
+
setup_fee: 800,
|
140
|
+
unit_amount: 10
|
141
|
+
}
|
142
|
+
]
|
143
|
+
}
|
144
|
+
|
145
|
+
plan = client.create_plan(body: plan_data)
|
146
|
+
```
|
147
|
+
|
148
|
+
### Error Handling
|
149
|
+
|
150
|
+
This library currently throws 2 types of exceptions. {Recurly::Errors::APIError} and {Recurly::Errors::NetworkError}. See these 2 files for the types of exceptions you can catch:
|
151
|
+
|
152
|
+
1. [API Errors](./lib/recurly/errors/api_errors.rb)
|
153
|
+
2. [Network Errors](./lib/recurly/errors/network_errors.rb)
|
154
|
+
|
155
|
+
You will normally be working with {Recurly::Errors::APIError}. You can catch specific or generic versions of these exceptions. Example:
|
156
|
+
|
157
|
+
```ruby
|
158
|
+
begin
|
159
|
+
client = Recurly::Client.new(api_key: API_KEY)
|
160
|
+
code = "iexistalready"
|
161
|
+
plan_data = {
|
162
|
+
code: code,
|
163
|
+
interval_length: 1,
|
164
|
+
interval_unit: 'months',
|
165
|
+
name: code,
|
166
|
+
currencies: [
|
167
|
+
{
|
168
|
+
currency: 'USD',
|
169
|
+
setup_fee: 800,
|
170
|
+
unit_amount: 10
|
171
|
+
}
|
172
|
+
]
|
173
|
+
}
|
174
|
+
|
175
|
+
plan = client.create_plan(body: plan_data)
|
176
|
+
rescue Recurly::Errors::ValidationError => ex
|
177
|
+
puts ex.inspect
|
178
|
+
#=> #<Recurly::ValidationError: Recurly::ValidationError: Code 'iexistalready' already exists>
|
179
|
+
puts ex.recurly_error.inspect
|
180
|
+
#=> #<Recurly::Error:0x007fbbdf8a32c8 @attributes={:type=>"validation", :message=>"Code 'iexistalready' already exists", :params=>[{"param"=>"code", "message"=>"'iexistalready' already exists"}]}>
|
181
|
+
puts ex.status_code
|
182
|
+
#=> 422
|
183
|
+
rescue Recurly::Errors::APIError => ex
|
184
|
+
# catch a generic api error
|
185
|
+
rescue Recurly::Errors::TimeoutError => ex
|
186
|
+
# catch a specific network error
|
187
|
+
rescue Recurly::Errors::NetworkError => ex
|
188
|
+
# catch a generic network error
|
189
|
+
end
|
190
|
+
```
|
191
|
+
|
192
|
+
### HTTP Metadata
|
193
|
+
|
194
|
+
Sometimes you might want to get some additional information about the underlying HTTP request and response. Instead of
|
195
|
+
returning this information directly and forcing the programmer to unwrap it, we inject this metadata into the top level
|
196
|
+
resource that was returned. You can access the {Recurly::HTTP::Response} by calling `#get_response` on any {Recurly::Resource}.
|
197
|
+
|
198
|
+
**Warning**: Do not log or render whole requests or responses as they may contain PII or sensitive data.
|
199
|
+
|
200
|
+
```ruby
|
201
|
+
account = @client.get_account(account_id: "code-benjamin")
|
202
|
+
response = account.get_response
|
203
|
+
response.rate_limit_remaining #=> 1985
|
204
|
+
response.request_id #=> "0av50sm5l2n2gkf88ehg"
|
205
|
+
response.request.path #=> "/sites/subdomain-mysite/accounts/code-benjamin"
|
206
|
+
response.request.body #=> None
|
207
|
+
```
|
208
|
+
|
209
|
+
This also works on {Recurly::Resources::Empty} responses:
|
210
|
+
|
211
|
+
```ruby
|
212
|
+
response = @client.remove_line_item(
|
213
|
+
line_item_id: "a959576b2b10b012"
|
214
|
+
).get_response
|
215
|
+
```
|
216
|
+
And it can be captured on exceptions through the {Recurly::ApiError} object:
|
217
|
+
|
218
|
+
```ruby
|
219
|
+
begin
|
220
|
+
account = client.get_account(account_id: "code-benjamin")
|
221
|
+
rescue Recurly::Errors::NotFoundError => e
|
222
|
+
response = e.get_response()
|
223
|
+
puts "Give this request id to Recurly Support: #{response.request_id}"
|
224
|
+
end
|
225
|
+
```
|
226
|
+
|
227
|
+
### Webhooks
|
228
|
+
|
229
|
+
Recurly can send webhooks to any publicly accessible server.
|
230
|
+
When an event in Recurly triggers a webhook (e.g., an account is opened),
|
231
|
+
Recurly will attempt to send this notification to the endpoint(s) you specify.
|
232
|
+
You can specify up to 10 endpoints through the application. All notifications will
|
233
|
+
be sent to all configured endpoints for your site.
|
234
|
+
|
235
|
+
See our [product docs](https://docs.recurly.com/docs/webhooks) to learn more about webhooks
|
236
|
+
and see our [dev docs](https://dev.recurly.com/page/webhooks) to learn about what payloads
|
237
|
+
are available.
|
238
|
+
|
239
|
+
Although our API is now JSON, our webhook payloads are still formatted as XML for the time being.
|
240
|
+
This library is not yet responsible for handling webhooks. If you do need webhooks, we recommend using a simple
|
241
|
+
XML to Hash parser.
|
242
|
+
|
243
|
+
If you are using Rails, we'd recommend [Hash.from_xml](https://apidock.com/rails/Hash/from_xml/class).
|
244
|
+
|
245
|
+
```ruby
|
246
|
+
notification = Hash.from_xml <<-XML
|
247
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
248
|
+
<new_account_notification>
|
249
|
+
<account>
|
250
|
+
<account_code>1</account_code>
|
251
|
+
<username nil="true"></username>
|
252
|
+
<email>verena@example.com</email>
|
253
|
+
<first_name>Verena</first_name>
|
254
|
+
<last_name>Example</last_name>
|
255
|
+
<company_name nil="true"></company_name>
|
256
|
+
</account>
|
257
|
+
</new_account_notification>
|
258
|
+
XML
|
259
|
+
|
260
|
+
code = notification["new_account_notification"]["account"]["account_code"]
|
261
|
+
puts "New Account with code #{code} created."
|
262
|
+
```
|
263
|
+
|
264
|
+
If you are not using Rails, we recommend you use [nokogiri](https://nokogiri.org/); however, heed security warnings
|
265
|
+
about parse options. Although the XML should only be coming from Recurly, you should parse it as untrusted to be safe.
|
266
|
+
Read more about the security implications of parsing untrusted XML in [this OWASP cheatsheet](https://cheatsheetseries.owasp.org/cheatsheets/XML_Security_Cheat_Sheet.html).
|
data/README.md
CHANGED
@@ -1,205 +1,23 @@
|
|
1
1
|
# Recurly
|
2
2
|
|
3
|
-
This
|
4
|
-
|
3
|
+
This repository houses the official ruby client for Recurly's V3 API.
|
4
|
+
|
5
|
+
> *Note*:
|
6
|
+
> If you were looking for the V2 client, see the [master branch](https://github.com/recurly/recurly-client-ruby/tree/master).
|
5
7
|
|
6
8
|
## Getting Started
|
7
9
|
|
8
10
|
### Documentation
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
### Installing
|
14
|
-
|
15
|
-
This gem is a pre-release. In your Gemfile, add `recurly` as a dependency.
|
16
|
-
|
17
|
-
```ruby
|
18
|
-
gem 'recurly', '3.0.0.beta.5'
|
19
|
-
```
|
20
|
-
|
21
|
-
It's important that you lock on a specific version as there may be breaking changes between releases.
|
22
|
-
All beta releases will have the format `3.0.0.beta.x` until we go live.
|
23
|
-
|
24
|
-
### Creating a client
|
25
|
-
|
26
|
-
Client instances are now explicitly created and referenced as opposed to V2's use of global, statically
|
27
|
-
initialized clients.
|
28
|
-
|
29
|
-
This makes multithreaded environments simpler and provides one location where every
|
30
|
-
operation can be found (rather than having them spread out among classes).
|
31
|
-
|
32
|
-
`Recurly::Client#new` initializes a new client. It requires an API key and a site id:
|
33
|
-
|
34
|
-
```ruby
|
35
|
-
API_KEY = '83749879bbde395b5fe0cc1a5abf8e5'
|
36
|
-
SITE_ID = 'dqzlv9shi7wa'
|
37
|
-
client = Recurly::Client.new(site_id: SITE_ID, api_key: API_KEY)
|
38
|
-
# You may use the subdomain instead of the site_id if you do not know the site_id
|
39
|
-
client = Recurly::Client.new(subdomain: 'mysite-prod', api_key: API_KEY)
|
40
|
-
sub = client.get_subscription(subscription_id: 'abcd123456')
|
41
|
-
```
|
42
|
-
|
43
|
-
You can also pass the initializer a block. This will give you a client scoped for just that block:
|
44
|
-
|
45
|
-
```ruby
|
46
|
-
Recurly::Client.new(subdomain: 'mysite-prod', api_key: API_KEY) do |client|
|
47
|
-
sub = client.get_subscription(subscription_id: 'abcd123456')
|
48
|
-
end
|
49
|
-
```
|
50
|
-
|
51
|
-
If you plan on using the client for more than one site, you should initialize a new client for each site.
|
52
|
-
|
53
|
-
```ruby
|
54
|
-
# Give a `site_id`
|
55
|
-
client = Recurly::Client.new(api_key: API_KEY, site_id: SITE_ID)
|
56
|
-
# Or use the subdomain
|
57
|
-
client = Recurly::Client.new(api_key: API_KEY, subdomain: 'mysite-dev')
|
58
|
-
|
59
|
-
sub = client.get_subscription(subscription_id: 'abcd123456')
|
60
|
-
|
61
|
-
# you should create a new client to connect to another site
|
62
|
-
client = Recurly::Client.new(api_key: API_KEY, subdomain: 'mysite-prod')
|
63
|
-
sub = client.get_subscription(subscription_id: 'abcd7890')
|
64
|
-
```
|
65
|
-
|
66
|
-
### Operations
|
67
|
-
|
68
|
-
The {Recurly::Client} contains every `operation` you can perform on the site as a list of methods. Each method is documented explaining
|
69
|
-
the types and descriptions for each input and return type. You can view all available operations by looking at the `Instance Methods Summary` list
|
70
|
-
on the {Recurly::Client} documentation page. Clicking a method will give you detailed information about its inputs and returns. Take the `create_account`
|
71
|
-
operation as an example: {Recurly::Client#create_account}.
|
72
|
-
|
73
|
-
### Pagination
|
74
|
-
|
75
|
-
Pagination is done by the class `Recurly::Pager`. All `list_*` methods on the client return an instance of this class.
|
76
|
-
The pager has an `each` method which accepts a block for each object in the entire list. Each page is fetched automatically
|
77
|
-
for you presenting the elements as a single enumerable.
|
78
|
-
|
79
|
-
```ruby
|
80
|
-
plans = client.list_plans()
|
81
|
-
plans.each do |plan|
|
82
|
-
puts "Plan: #{plan.id}"
|
83
|
-
end
|
84
|
-
```
|
85
|
-
|
86
|
-
You may also paginate in chunks with `each_page`.
|
87
|
-
|
88
|
-
```ruby
|
89
|
-
plans = client.list_plans()
|
90
|
-
plans.each_page do |data|
|
91
|
-
data.each do |plan|
|
92
|
-
puts "Plan: #{plan.id}"
|
93
|
-
end
|
94
|
-
end
|
95
|
-
```
|
96
|
-
|
97
|
-
Both `Pager#each` and `Pager#each_page` return Enumerators if a block is not given. This allows you to use other Enumerator methods
|
98
|
-
such as `map` or `each_with_index`.
|
99
|
-
|
100
|
-
```ruby
|
101
|
-
plans = client.list_plans()
|
102
|
-
plans.each_page.each_with_index do |data, page_num|
|
103
|
-
puts "Page Number #{page_num}"
|
104
|
-
data.each do |plan|
|
105
|
-
puts "Plan: #{plan.id}"
|
106
|
-
end
|
107
|
-
end
|
108
|
-
```
|
109
|
-
|
110
|
-
Pagination endpoints take a number of options to sort and filter the results. They can be passed in as keyword arguments.
|
111
|
-
The names, types, and descriptions of these arguments are listed in the rubydocs for each method:
|
112
|
-
|
113
|
-
```ruby
|
114
|
-
options = {
|
115
|
-
limit: 200, # number of items per page
|
116
|
-
state: :active, # only active plans
|
117
|
-
sort: :updated_at,
|
118
|
-
order: :asc,
|
119
|
-
begin_time: DateTime.new(2017,1,1), # January 1st 2017,
|
120
|
-
end_time: DateTime.now
|
121
|
-
}
|
122
|
-
|
123
|
-
plans = client.list_plans(**options)
|
124
|
-
plans.each do |plan|
|
125
|
-
puts "Plan: #{plan.id}"
|
126
|
-
end
|
127
|
-
```
|
128
|
-
|
129
|
-
**A note on `limit`**:
|
130
|
-
|
131
|
-
`limit` defaults to 20 items per page and can be set from 1 to 200. Choosing a lower limit means more network requests but smaller payloads.
|
132
|
-
We recommend keeping the default for most cases but increasing the limit if you are planning on iterating through many pages of items (e.g. all transactions in your site).
|
133
|
-
|
134
|
-
|
135
|
-
### Creating Resources
|
136
|
-
|
137
|
-
Currently, resources are created by passing in a `body` keyword argument in the form of a `Hash`.
|
138
|
-
This Hash must follow the schema of the documented request type. For example, the `create_plan` operation
|
139
|
-
takes a request of type {Recurly::Requests::PlanCreate}. Failing to conform to this schema will result in an argument
|
140
|
-
error.
|
141
|
-
|
142
|
-
```ruby
|
143
|
-
require 'securerandom'
|
144
|
-
|
145
|
-
code = SecureRandom.uuid
|
146
|
-
plan_data = {
|
147
|
-
code: code,
|
148
|
-
interval_length: 1,
|
149
|
-
interval_unit: 'months',
|
150
|
-
name: code,
|
151
|
-
currencies: [
|
152
|
-
{
|
153
|
-
currency: 'USD',
|
154
|
-
setup_fee: 800,
|
155
|
-
unit_amount: 10
|
156
|
-
}
|
157
|
-
]
|
158
|
-
}
|
159
|
-
|
160
|
-
plan = client.create_plan(body: plan_data)
|
161
|
-
```
|
162
|
-
|
163
|
-
### Error Handling
|
164
|
-
|
165
|
-
This library currently throws 2 types of exceptions. {Recurly::Errors::APIError} and {Recurly::Errors::NetworkError}. See these 2 files for the types of exceptions you can catch:
|
12
|
+
> *Note*:
|
13
|
+
> Until rubydoc.info respects our `.yardopts` file, see documentation [here](GETTING_STARTED.md).
|
166
14
|
|
167
|
-
|
168
|
-
|
15
|
+
Ruby documentation and the getting started instructions can be found
|
16
|
+
on rubydoc.info: [https://www.rubydoc.info/github/recurly/recurly-client-ruby/](https://www.rubydoc.info/github/recurly/recurly-client-ruby/).
|
169
17
|
|
170
|
-
|
18
|
+
Documentation for the HTTP API and example code can be found
|
19
|
+
[on our Developer Portal](https://developers.recurly.com/api/v2019-10-10/).
|
171
20
|
|
172
|
-
|
173
|
-
begin
|
174
|
-
client = Recurly::Client.new(site_id: SITE_ID, api_key: API_KEY)
|
175
|
-
code = "iexistalready"
|
176
|
-
plan_data = {
|
177
|
-
code: code,
|
178
|
-
interval_length: 1,
|
179
|
-
interval_unit: 'months',
|
180
|
-
name: code,
|
181
|
-
currencies: [
|
182
|
-
{
|
183
|
-
currency: 'USD',
|
184
|
-
setup_fee: 800,
|
185
|
-
unit_amount: 10
|
186
|
-
}
|
187
|
-
]
|
188
|
-
}
|
21
|
+
### Contributing
|
189
22
|
|
190
|
-
|
191
|
-
rescue Recurly::Errors::ValidationError => ex
|
192
|
-
puts ex.inspect
|
193
|
-
#=> #<Recurly::ValidationError: Recurly::ValidationError: Code 'iexistalready' already exists>
|
194
|
-
puts ex.recurly_error.inspect
|
195
|
-
#=> #<Recurly::Error:0x007fbbdf8a32c8 @attributes={:type=>"validation", :message=>"Code 'iexistalready' already exists", :params=>[{"param"=>"code", "message"=>"'iexistalready' already exists"}]}>
|
196
|
-
puts ex.status_code
|
197
|
-
#=> 422
|
198
|
-
rescue Recurly::Errors::APIError => ex
|
199
|
-
# catch a generic api error
|
200
|
-
rescue Recurly::Errors::TimeoutError => ex
|
201
|
-
# catch a specific network error
|
202
|
-
rescue Recurly::Errors::NetworkError => ex
|
203
|
-
# catch a generic network error
|
204
|
-
end
|
205
|
-
```
|
23
|
+
Please see our [Contributing Guide](CONTRIBUTING.md).
|