airwallex 0.1.0 → 0.3.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 +35 -0
- data/README.md +166 -7
- data/lib/airwallex/api_operations/list.rb +27 -8
- data/lib/airwallex/errors.rb +1 -0
- data/lib/airwallex/resources/balance.rb +59 -0
- data/lib/airwallex/resources/batch_transfer.rb +32 -0
- data/lib/airwallex/resources/conversion.rb +43 -0
- data/lib/airwallex/resources/customer.rb +40 -0
- data/lib/airwallex/resources/dispute.rb +68 -0
- data/lib/airwallex/resources/payment_method.rb +51 -0
- data/lib/airwallex/resources/quote.rb +51 -0
- data/lib/airwallex/resources/rate.rb +33 -0
- data/lib/airwallex/resources/refund.rb +34 -0
- data/lib/airwallex/version.rb +1 -1
- data/lib/airwallex.rb +9 -0
- metadata +16 -15
- data/docs/internal/20251125_iteration_1_quickstart.md +0 -130
- data/docs/internal/20251125_iteration_1_summary.md +0 -342
- data/docs/internal/20251125_sprint_1_completed.md +0 -448
- data/docs/internal/20251125_sprint_1_plan.md +0 -389
- data/docs/internal/20251125_sprint_2_completed.md +0 -559
- data/docs/internal/20251125_sprint_2_plan.md +0 -531
- data/docs/internal/20251125_sprint_2_unit_tests_completed.md +0 -264
- data/docs/research/Airwallex API Endpoint Research.md +0 -410
- data/docs/research/Airwallex API Research for Ruby Gem.md +0 -383
|
@@ -1,389 +0,0 @@
|
|
|
1
|
-
# Sprint 1 Implementation Plan
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
Sprint 1 focuses on establishing the foundational architecture of the Airwallex Ruby gem, including core infrastructure, authentication mechanisms, and basic API communication capabilities. This sprint prioritizes correctness, idempotency, and type safety as outlined in the architectural blueprint.
|
|
6
|
-
|
|
7
|
-
## Sprint Goals
|
|
8
|
-
|
|
9
|
-
1. Establish core gem architecture and configuration system
|
|
10
|
-
2. Implement authentication and token lifecycle management
|
|
11
|
-
3. Build HTTP transport layer with Faraday
|
|
12
|
-
4. Create error handling framework
|
|
13
|
-
5. Implement idempotency middleware
|
|
14
|
-
6. Set up testing infrastructure
|
|
15
|
-
|
|
16
|
-
## Sprint Duration
|
|
17
|
-
|
|
18
|
-
2 weeks
|
|
19
|
-
|
|
20
|
-
## Work Items
|
|
21
|
-
|
|
22
|
-
### 1. Core Architecture Setup
|
|
23
|
-
|
|
24
|
-
**Priority: Critical**
|
|
25
|
-
|
|
26
|
-
#### 1.1 Gem Structure and Module Organization
|
|
27
|
-
|
|
28
|
-
- Create directory structure following the architectural blueprint:
|
|
29
|
-
```
|
|
30
|
-
lib/airwallex/
|
|
31
|
-
├── api_operations/
|
|
32
|
-
├── resources/
|
|
33
|
-
├── errors.rb
|
|
34
|
-
├── client.rb
|
|
35
|
-
├── configuration.rb
|
|
36
|
-
├── webhook.rb
|
|
37
|
-
├── util.rb
|
|
38
|
-
├── middleware/
|
|
39
|
-
│ ├── auth_refresh.rb
|
|
40
|
-
│ └── idempotency.rb
|
|
41
|
-
└── version.rb
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
- Set up `lib/airwallex.rb` as main entry point with configuration block support
|
|
45
|
-
|
|
46
|
-
**Acceptance Criteria:**
|
|
47
|
-
- Directory structure matches blueprint
|
|
48
|
-
- Module can be required without errors
|
|
49
|
-
- Configuration block accepts environment, api_key, client_id
|
|
50
|
-
|
|
51
|
-
**Estimated Effort:** 2 hours
|
|
52
|
-
|
|
53
|
-
#### 1.2 Configuration Management
|
|
54
|
-
|
|
55
|
-
- Implement `Airwallex::Configuration` class
|
|
56
|
-
- Support environment selection (`:sandbox`, `:production`)
|
|
57
|
-
- Dynamic URL generation based on environment
|
|
58
|
-
- Default to `:sandbox` for safety
|
|
59
|
-
- Validate credential format
|
|
60
|
-
|
|
61
|
-
**Key Features:**
|
|
62
|
-
```ruby
|
|
63
|
-
Airwallex.configure do |config|
|
|
64
|
-
config.api_key = 'key'
|
|
65
|
-
config.client_id = 'id'
|
|
66
|
-
config.environment = :sandbox
|
|
67
|
-
config.api_version = '2024-09-27' # Date-based versioning
|
|
68
|
-
end
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
**Acceptance Criteria:**
|
|
72
|
-
- Configuration persists across requests
|
|
73
|
-
- Environment correctly maps to URLs (api-demo vs api)
|
|
74
|
-
- Raises error if credentials missing
|
|
75
|
-
- Validates environment is :sandbox or :production
|
|
76
|
-
|
|
77
|
-
**Estimated Effort:** 4 hours
|
|
78
|
-
|
|
79
|
-
### 2. HTTP Transport Layer
|
|
80
|
-
|
|
81
|
-
**Priority: Critical**
|
|
82
|
-
|
|
83
|
-
#### 2.1 Faraday Client Setup
|
|
84
|
-
|
|
85
|
-
- Configure Faraday connection with TLS 1.2+ enforcement
|
|
86
|
-
- Set base URLs for API and Files endpoints
|
|
87
|
-
- Configure default headers:
|
|
88
|
-
- `Content-Type: application/json`
|
|
89
|
-
- `User-Agent: Airwallex-Ruby/{version} Ruby/{ruby_version}`
|
|
90
|
-
- `x-api-version` from configuration
|
|
91
|
-
|
|
92
|
-
**Acceptance Criteria:**
|
|
93
|
-
- Faraday connection established
|
|
94
|
-
- Headers correctly injected
|
|
95
|
-
- TLS version enforced
|
|
96
|
-
- Base URL switches with environment
|
|
97
|
-
|
|
98
|
-
**Estimated Effort:** 3 hours
|
|
99
|
-
|
|
100
|
-
#### 2.2 Request/Response Middleware Stack
|
|
101
|
-
|
|
102
|
-
- JSON request encoding
|
|
103
|
-
- JSON response parsing
|
|
104
|
-
- Logging middleware (debug mode)
|
|
105
|
-
- Configure connection and request timeouts
|
|
106
|
-
|
|
107
|
-
**Acceptance Criteria:**
|
|
108
|
-
- JSON automatically serialized/deserialized
|
|
109
|
-
- Logs show request/response in debug mode
|
|
110
|
-
- Timeouts configurable
|
|
111
|
-
|
|
112
|
-
**Estimated Effort:** 3 hours
|
|
113
|
-
|
|
114
|
-
### 3. Authentication System
|
|
115
|
-
|
|
116
|
-
**Priority: Critical**
|
|
117
|
-
|
|
118
|
-
#### 3.1 Bearer Token Authentication
|
|
119
|
-
|
|
120
|
-
- Implement `Airwallex::Authentication` module
|
|
121
|
-
- POST to `/api/v1/authentication/login`
|
|
122
|
-
- Exchange client_id/api_key for Bearer token
|
|
123
|
-
- Store token and expiration
|
|
124
|
-
|
|
125
|
-
**Key Implementation:**
|
|
126
|
-
```ruby
|
|
127
|
-
POST /api/v1/authentication/login
|
|
128
|
-
Headers: x-client-id, x-api-key
|
|
129
|
-
Response: { token: "...", expires_at: "..." }
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
**Acceptance Criteria:**
|
|
133
|
-
- Successful token exchange
|
|
134
|
-
- Token stored in client instance
|
|
135
|
-
- Expiration time tracked
|
|
136
|
-
- Handles 401 authentication errors
|
|
137
|
-
|
|
138
|
-
**Estimated Effort:** 4 hours
|
|
139
|
-
|
|
140
|
-
#### 3.2 Token Lifecycle Management Middleware
|
|
141
|
-
|
|
142
|
-
- Implement `Airwallex::Middleware::AuthRefresh`
|
|
143
|
-
- Check token expiration before requests (5-minute buffer)
|
|
144
|
-
- Auto-refresh expired tokens
|
|
145
|
-
- Intercept 401 responses and retry once after refresh
|
|
146
|
-
- Thread-safe token management
|
|
147
|
-
|
|
148
|
-
**Acceptance Criteria:**
|
|
149
|
-
- Token refreshes automatically when expired
|
|
150
|
-
- 401 responses trigger refresh and retry
|
|
151
|
-
- No double-refresh in concurrent requests
|
|
152
|
-
- Transparent to end user
|
|
153
|
-
|
|
154
|
-
**Estimated Effort:** 6 hours
|
|
155
|
-
|
|
156
|
-
### 4. Error Handling Framework
|
|
157
|
-
|
|
158
|
-
**Priority: Critical**
|
|
159
|
-
|
|
160
|
-
#### 4.1 Exception Hierarchy
|
|
161
|
-
|
|
162
|
-
Create exception classes mapped to HTTP status codes:
|
|
163
|
-
|
|
164
|
-
```ruby
|
|
165
|
-
Airwallex::Error (base)
|
|
166
|
-
├── Airwallex::BadRequestError (400)
|
|
167
|
-
├── Airwallex::AuthenticationError (401)
|
|
168
|
-
├── Airwallex::PermissionError (403)
|
|
169
|
-
├── Airwallex::NotFoundError (404)
|
|
170
|
-
├── Airwallex::RateLimitError (429)
|
|
171
|
-
└── Airwallex::APIError (500+)
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
**Acceptance Criteria:**
|
|
175
|
-
- All error classes defined
|
|
176
|
-
- Base error has code, message, param, details attributes
|
|
177
|
-
- HTTP status correctly mapped to exception class
|
|
178
|
-
|
|
179
|
-
**Estimated Effort:** 3 hours
|
|
180
|
-
|
|
181
|
-
#### 4.2 Error Response Parsing
|
|
182
|
-
|
|
183
|
-
- Handle polymorphic error body structures
|
|
184
|
-
- Parse standard errors: `{ code, message, source }`
|
|
185
|
-
- Parse complex errors with details array
|
|
186
|
-
- Parse validation errors with nested source paths
|
|
187
|
-
- Map `source` to `param` attribute
|
|
188
|
-
|
|
189
|
-
**Test Cases:**
|
|
190
|
-
- Simple error: `{ code: "insufficient_fund", message: "..." }`
|
|
191
|
-
- Complex error: `{ code: "request_id_duplicate", details: [...] }`
|
|
192
|
-
- Validation error: `{ code: "invalid_argument", source: "nested.field.path" }`
|
|
193
|
-
|
|
194
|
-
**Acceptance Criteria:**
|
|
195
|
-
- All error formats parsed correctly
|
|
196
|
-
- Detailed error information accessible
|
|
197
|
-
- Source field mapped to param
|
|
198
|
-
|
|
199
|
-
**Estimated Effort:** 4 hours
|
|
200
|
-
|
|
201
|
-
### 5. Idempotency System
|
|
202
|
-
|
|
203
|
-
**Priority: High**
|
|
204
|
-
|
|
205
|
-
#### 5.1 Idempotency Middleware
|
|
206
|
-
|
|
207
|
-
- Implement `Airwallex::Middleware::Idempotency`
|
|
208
|
-
- Auto-generate UUID v4 for `request_id` if not provided
|
|
209
|
-
- Inject `request_id` into request body (not headers)
|
|
210
|
-
- Preserve user-provided request_id for reconciliation
|
|
211
|
-
|
|
212
|
-
**Key Behavior:**
|
|
213
|
-
```ruby
|
|
214
|
-
# User doesn't provide request_id
|
|
215
|
-
Transfer.create(amount: 100)
|
|
216
|
-
# Gem generates: { amount: 100, request_id: "uuid-v4" }
|
|
217
|
-
|
|
218
|
-
# User provides request_id
|
|
219
|
-
Transfer.create(amount: 100, request_id: "my-id")
|
|
220
|
-
# Gem preserves: { amount: 100, request_id: "my-id" }
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
**Acceptance Criteria:**
|
|
224
|
-
- UUID v4 generated if request_id missing
|
|
225
|
-
- User-provided request_id preserved
|
|
226
|
-
- request_id injected into body, not headers
|
|
227
|
-
- Works for POST/PUT/PATCH methods only
|
|
228
|
-
|
|
229
|
-
**Estimated Effort:** 4 hours
|
|
230
|
-
|
|
231
|
-
#### 5.2 Retry Logic with Idempotency
|
|
232
|
-
|
|
233
|
-
- Implement retry middleware with exponential backoff
|
|
234
|
-
- Safe retries for GET requests on 429, 5xx
|
|
235
|
-
- Safe retries for POST/PUT/PATCH only if request_id present
|
|
236
|
-
- Jittered exponential backoff (prevents thundering herd)
|
|
237
|
-
- Max 3 retry attempts
|
|
238
|
-
|
|
239
|
-
**Acceptance Criteria:**
|
|
240
|
-
- GET requests retried on 429/5xx
|
|
241
|
-
- POST with request_id retried safely
|
|
242
|
-
- POST without request_id NOT retried
|
|
243
|
-
- Backoff includes jitter
|
|
244
|
-
- Max retries configurable
|
|
245
|
-
|
|
246
|
-
**Estimated Effort:** 5 hours
|
|
247
|
-
|
|
248
|
-
### 6. Testing Infrastructure
|
|
249
|
-
|
|
250
|
-
**Priority: High**
|
|
251
|
-
|
|
252
|
-
#### 6.1 Test Setup
|
|
253
|
-
|
|
254
|
-
- Configure RSpec with spec_helper
|
|
255
|
-
- Add WebMock for HTTP stubbing
|
|
256
|
-
- Add VCR for recording/replaying HTTP interactions
|
|
257
|
-
- Create test fixtures for common responses
|
|
258
|
-
- Set up test coverage reporting
|
|
259
|
-
|
|
260
|
-
**Acceptance Criteria:**
|
|
261
|
-
- RSpec runs successfully
|
|
262
|
-
- WebMock blocks real HTTP requests
|
|
263
|
-
- VCR configured for sandbox interactions
|
|
264
|
-
- Test coverage tracked
|
|
265
|
-
|
|
266
|
-
**Estimated Effort:** 3 hours
|
|
267
|
-
|
|
268
|
-
#### 6.2 Core Tests
|
|
269
|
-
|
|
270
|
-
Write comprehensive tests for:
|
|
271
|
-
|
|
272
|
-
- Configuration management
|
|
273
|
-
- Authentication flow
|
|
274
|
-
- Token refresh logic
|
|
275
|
-
- Error parsing (all formats)
|
|
276
|
-
- Idempotency key generation
|
|
277
|
-
- Retry logic with various scenarios
|
|
278
|
-
|
|
279
|
-
**Test Coverage Targets:**
|
|
280
|
-
- Configuration: 100%
|
|
281
|
-
- Authentication: 100%
|
|
282
|
-
- Error handling: 100%
|
|
283
|
-
- Middleware: 95%+
|
|
284
|
-
|
|
285
|
-
**Acceptance Criteria:**
|
|
286
|
-
- All core components tested
|
|
287
|
-
- Edge cases covered
|
|
288
|
-
- VCR cassettes for sandbox API
|
|
289
|
-
- Coverage above 90%
|
|
290
|
-
|
|
291
|
-
**Estimated Effort:** 8 hours
|
|
292
|
-
|
|
293
|
-
### 7. Utility Modules
|
|
294
|
-
|
|
295
|
-
**Priority: Medium**
|
|
296
|
-
|
|
297
|
-
#### 7.1 Date/Time Formatting
|
|
298
|
-
|
|
299
|
-
- Implement ISO 8601 serialization helpers
|
|
300
|
-
- Accept Ruby Date, Time, DateTime objects
|
|
301
|
-
- Convert to "YYYY-MM-DDTHH:MM:SSZ" format
|
|
302
|
-
- Handle timezone conversions
|
|
303
|
-
|
|
304
|
-
**Acceptance Criteria:**
|
|
305
|
-
- Date/Time objects serialized correctly
|
|
306
|
-
- ISO 8601 format enforced
|
|
307
|
-
- Timezone handling accurate
|
|
308
|
-
|
|
309
|
-
**Estimated Effort:** 2 hours
|
|
310
|
-
|
|
311
|
-
#### 7.2 BigDecimal Support
|
|
312
|
-
|
|
313
|
-
- Configure JSON serialization for BigDecimal
|
|
314
|
-
- Add helpers for currency conversion
|
|
315
|
-
- Documentation on monetary value handling
|
|
316
|
-
|
|
317
|
-
**Acceptance Criteria:**
|
|
318
|
-
- BigDecimal serialized without precision loss
|
|
319
|
-
- Helper methods available
|
|
320
|
-
- Documentation clear
|
|
321
|
-
|
|
322
|
-
**Estimated Effort:** 2 hours
|
|
323
|
-
|
|
324
|
-
## Definition of Done
|
|
325
|
-
|
|
326
|
-
- [ ] All code follows Rubocop style guide (no offenses)
|
|
327
|
-
- [ ] Test coverage above 90%
|
|
328
|
-
- [ ] All acceptance criteria met
|
|
329
|
-
- [ ] Documentation updated in README
|
|
330
|
-
- [ ] Code reviewed by team member
|
|
331
|
-
- [ ] Manual testing in sandbox environment
|
|
332
|
-
- [ ] No security vulnerabilities (bundle audit clean)
|
|
333
|
-
|
|
334
|
-
## Dependencies and Risks
|
|
335
|
-
|
|
336
|
-
### Dependencies
|
|
337
|
-
|
|
338
|
-
- Faraday ~> 2.0
|
|
339
|
-
- Faraday-multipart ~> 1.0
|
|
340
|
-
- Faraday-retry ~> 2.0
|
|
341
|
-
- RSpec ~> 3.12 (dev)
|
|
342
|
-
- WebMock ~> 3.18 (dev)
|
|
343
|
-
- VCR ~> 6.1 (dev)
|
|
344
|
-
|
|
345
|
-
### Risks
|
|
346
|
-
|
|
347
|
-
1. **Token refresh race conditions**: Mitigated with mutex locks
|
|
348
|
-
2. **Idempotency key collisions**: Use UUID v4 (collision probability negligible)
|
|
349
|
-
3. **API version changes**: Pin to specific tested version (2024-09-27)
|
|
350
|
-
4. **Rate limiting during testing**: Use VCR to replay responses
|
|
351
|
-
|
|
352
|
-
## Success Metrics
|
|
353
|
-
|
|
354
|
-
- Core architecture complete and testable
|
|
355
|
-
- Authentication works reliably in sandbox
|
|
356
|
-
- Idempotency prevents duplicate transactions
|
|
357
|
-
- Error handling provides actionable information
|
|
358
|
-
- All tests pass consistently
|
|
359
|
-
- Zero Rubocop offenses
|
|
360
|
-
|
|
361
|
-
## Out of Scope for Sprint 1
|
|
362
|
-
|
|
363
|
-
The following items are deferred to future sprints:
|
|
364
|
-
|
|
365
|
-
- Specific resource implementations (Payment, Transfer, etc.)
|
|
366
|
-
- Pagination logic (AutoPaginator)
|
|
367
|
-
- Webhook signature verification
|
|
368
|
-
- OAuth flow support
|
|
369
|
-
- SCA token handling
|
|
370
|
-
- Platform/Connected Account features (x-on-behalf-of)
|
|
371
|
-
- Rate limit headers parsing
|
|
372
|
-
- API version override per-request
|
|
373
|
-
|
|
374
|
-
## Sprint Retrospective Topics
|
|
375
|
-
|
|
376
|
-
- Was the architectural approach correct?
|
|
377
|
-
- Are the abstractions at the right level?
|
|
378
|
-
- Is the error handling sufficient?
|
|
379
|
-
- How maintainable is the middleware stack?
|
|
380
|
-
- What surprised us during implementation?
|
|
381
|
-
|
|
382
|
-
## Next Sprint Preview
|
|
383
|
-
|
|
384
|
-
Sprint 2 will focus on:
|
|
385
|
-
- Resource base class (APIResource)
|
|
386
|
-
- API operations mixins (Create, Retrieve, List)
|
|
387
|
-
- Pagination system (cursor and offset)
|
|
388
|
-
- First resource implementations (Payment Intent, Transfer)
|
|
389
|
-
- Webhook verification
|