payload-api 0.0.0 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +77 -5
- data/lib/payload.rb +11 -1
- data/lib/payload/arm/object.rb +85 -0
- data/lib/payload/arm/request.rb +145 -0
- data/lib/payload/exceptions.rb +48 -0
- data/lib/payload/objects.rb +79 -0
- data/lib/payload/utils.rb +38 -0
- data/lib/payload/version.rb +1 -1
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0711e29f8e4a39b865cda04ddc414b3b34c38d8b9f9314f785410fb4f1346c7e
|
4
|
+
data.tar.gz: 04cfdc8927d2c47e16db1ceaf8aff90c54b8e87bb1cb57b6e4edc907755f44b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e2f51ded017699686030ca7c8c4ab38ebcdbf3efd11f416a467c2aac5435b68b7935b9802429f2665338e2bc5e886aa0b3399d06a881ac3d89a382200e0a2ce4
|
7
|
+
data.tar.gz: 82c40295cc2a47068ad93cf7dcce41c1bdaef381fde723aefb07da4826d6d52a0284b45f343b9eb6cf07d1762481e0b8bfea380d760eec33bf3a2002a27019cc
|
data/README.md
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# Payload RubyGem
|
2
2
|
|
3
|
-
A RubyGem for
|
3
|
+
A RubyGem for integrating [Payload](https://payload.co).
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
7
7
|
To install using [Bundler](https://bundler.io):
|
8
8
|
|
9
9
|
```ruby
|
10
|
-
gem '
|
10
|
+
gem 'payload-api', '~> 0.1.0'
|
11
11
|
```
|
12
12
|
|
13
13
|
To install using gem:
|
@@ -16,9 +16,81 @@ To install using gem:
|
|
16
16
|
gem install payload
|
17
17
|
```
|
18
18
|
|
19
|
+
## Get Started
|
19
20
|
|
20
|
-
|
21
|
-
|
21
|
+
Once you've installed the Payload Python library to your environment,
|
22
|
+
import the `payload` module to get started. **Note:** We recommend
|
23
|
+
using the shorthand name of `pl` when importing.
|
24
|
+
|
25
|
+
```python
|
26
|
+
import payload as pl
|
27
|
+
```
|
28
|
+
|
29
|
+
### API Authentication
|
30
|
+
|
31
|
+
To authenticate with the Payload API, you'll need a live or test API key. API
|
32
|
+
keys are accessible from within the Payload dashboard.
|
33
|
+
|
34
|
+
```python
|
35
|
+
import payload as pl
|
36
|
+
pl.api_key = 'secret_key_3bW9JMZtPVDOfFNzwRdfE'
|
37
|
+
```
|
38
|
+
|
39
|
+
### Creating an Object
|
40
|
+
|
41
|
+
Interfacing with the Payload API is done primarily through Payload Objects. Below is an example of
|
42
|
+
creating a customer using the `Payload::Customer` object.
|
43
|
+
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
# Create a Customer
|
47
|
+
customer = Payload::Customer.create(
|
48
|
+
email: 'matt.perez@example.com',
|
49
|
+
full_name: 'Matt Perez'
|
50
|
+
)
|
51
|
+
```
|
52
|
+
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
# Create a Payment
|
56
|
+
payment = Payload::Payment.create(
|
57
|
+
amount: 100.0,
|
58
|
+
payment_method: Payload::Card(
|
59
|
+
card_number: '4242 4242 4242 4242'
|
60
|
+
)
|
61
|
+
)
|
62
|
+
```
|
63
|
+
|
64
|
+
### Accessing Object Attributes
|
65
|
+
|
66
|
+
Object attributes are accessible through both dot and bracket notation.
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
customer.name
|
70
|
+
customer['name']
|
71
|
+
```
|
72
|
+
|
73
|
+
### Updating an Object
|
74
|
+
|
75
|
+
Updating an object is a simple call to the `update` object method.
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
# Updating a customer's email
|
79
|
+
customer.update( email: 'matt.perez@newwork.com' )
|
80
|
+
```
|
81
|
+
|
82
|
+
### Selecting Objects
|
83
|
+
|
84
|
+
Objects can be selected using any of their attributes.
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
# Select a customer by email
|
88
|
+
customers = Payload::Customer.filter_by(
|
89
|
+
email: 'matt.perez@example.com'
|
90
|
+
)
|
91
|
+
```
|
22
92
|
|
23
93
|
## Documentation
|
24
|
-
|
94
|
+
|
95
|
+
To get further information on Payload's RubyGem and API capabilities,
|
96
|
+
visit the unabridged [Payload Documentation](https://docs.payload.co/?ruby).
|
data/lib/payload.rb
CHANGED
@@ -1,6 +1,16 @@
|
|
1
|
-
require "
|
1
|
+
require "payload/version"
|
2
|
+
require "payload/objects"
|
2
3
|
|
3
4
|
module Payload
|
5
|
+
@URL = "https://api.payload.co"
|
6
|
+
@api_url = @URL
|
7
|
+
@api_key = nil
|
8
|
+
|
4
9
|
class << self
|
10
|
+
attr_accessor :api_key, :api_url
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.create(objects)
|
14
|
+
return Payload::ARMRequest.new().create(objects)
|
5
15
|
end
|
6
16
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require "payload/arm/request"
|
2
|
+
|
3
|
+
module Payload
|
4
|
+
class ARMObject
|
5
|
+
@poly = nil
|
6
|
+
@data = nil
|
7
|
+
@@cache = {}
|
8
|
+
|
9
|
+
class << self
|
10
|
+
attr_reader :spec, :poly, :data
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(data)
|
14
|
+
self.set_data(data)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.new(data)
|
18
|
+
if data.key?('id') and @@cache.key?(data['id'])
|
19
|
+
@@cache[data['id']].set_data(data)
|
20
|
+
return @@cache[data['id']]
|
21
|
+
else
|
22
|
+
inst = super
|
23
|
+
if data.key?('id') and not data['id'].nil? and not data['id'].empty?
|
24
|
+
@@cache[data['id']] = inst
|
25
|
+
end
|
26
|
+
|
27
|
+
return inst
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def data
|
32
|
+
@data
|
33
|
+
end
|
34
|
+
|
35
|
+
def set_data(data)
|
36
|
+
@data = data
|
37
|
+
end
|
38
|
+
|
39
|
+
def method_missing(name, *args)
|
40
|
+
attr = name.to_s
|
41
|
+
if @data.key?(attr)
|
42
|
+
return @data[attr]
|
43
|
+
else
|
44
|
+
super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def [](key)
|
49
|
+
return @data[key]
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.select(*args, **data)
|
53
|
+
return Payload::ARMRequest.new(self).select(*args, **data)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.filter_by(*args, **data)
|
57
|
+
return Payload::ARMRequest.new(self).filter_by(*args, **data)
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.create(*args, **data)
|
61
|
+
if args.length != 0
|
62
|
+
return Payload::ARMRequest.new(self).create(args[0])
|
63
|
+
else
|
64
|
+
return Payload::ARMRequest.new(self).create(data)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.get(id)
|
69
|
+
return Payload::ARMRequest.new(self).get(id)
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.delete(objects)
|
73
|
+
return Payload::ARMRequest.new(self).delete(objects)
|
74
|
+
end
|
75
|
+
|
76
|
+
def update(**update)
|
77
|
+
return Payload::ARMRequest.new(self.class)._request('Put', id: self.id, json: update)
|
78
|
+
end
|
79
|
+
|
80
|
+
def delete()
|
81
|
+
return Payload::ARMRequest.new(self.class)._request('Delete', id: self.id)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require "payload/exceptions"
|
2
|
+
require "payload/utils"
|
3
|
+
require "net/http"
|
4
|
+
require "uri"
|
5
|
+
require "json"
|
6
|
+
|
7
|
+
module Payload
|
8
|
+
class ARMRequest
|
9
|
+
@cls = nil
|
10
|
+
|
11
|
+
def initialize(cls=nil)
|
12
|
+
@cls = cls
|
13
|
+
@filters = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def select(*args, **data)
|
17
|
+
if @cls.poly
|
18
|
+
data = data.merge(@cls.poly)
|
19
|
+
end
|
20
|
+
|
21
|
+
return self
|
22
|
+
end
|
23
|
+
|
24
|
+
def filter_by(*args, **data)
|
25
|
+
if @cls.poly
|
26
|
+
data = data.merge(@cls.poly)
|
27
|
+
end
|
28
|
+
|
29
|
+
@filters = @filters.merge(data)
|
30
|
+
|
31
|
+
return self
|
32
|
+
end
|
33
|
+
|
34
|
+
def all()
|
35
|
+
return self._request('Get')
|
36
|
+
end
|
37
|
+
|
38
|
+
def get(id)
|
39
|
+
if id.nil? || id.empty?
|
40
|
+
throw 'id cannot be empty'
|
41
|
+
end
|
42
|
+
|
43
|
+
return self._request('Get', id: id)
|
44
|
+
end
|
45
|
+
|
46
|
+
def update(**updates)
|
47
|
+
return self.filter_by(mode: 'query')
|
48
|
+
._request('Put', json: updates)
|
49
|
+
end
|
50
|
+
|
51
|
+
def delete(objects)
|
52
|
+
deletes = objects.map {|o| o.id }.join('|')
|
53
|
+
return self.filter_by(mode: 'query', id: deletes)
|
54
|
+
._request('Delete')
|
55
|
+
end
|
56
|
+
|
57
|
+
def create(data)
|
58
|
+
if data.is_a? Array
|
59
|
+
data = data.map do |obj|
|
60
|
+
if obj.kind_of?(ARMObject)
|
61
|
+
if @cls and not obj.instance_of?(@cls)
|
62
|
+
throw "All objects must be of the same type"
|
63
|
+
end
|
64
|
+
|
65
|
+
@cls = obj.class
|
66
|
+
obj = obj.data
|
67
|
+
end
|
68
|
+
|
69
|
+
if @cls.poly
|
70
|
+
obj = obj.merge(@cls.poly)
|
71
|
+
end
|
72
|
+
|
73
|
+
obj
|
74
|
+
end
|
75
|
+
|
76
|
+
data = { object: 'list', values: data }
|
77
|
+
else
|
78
|
+
if @cls.poly
|
79
|
+
data = data.merge(@cls.poly)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
return self._request('Post', json: data)
|
84
|
+
end
|
85
|
+
|
86
|
+
def _request(method, id: nil, json: nil)
|
87
|
+
if @cls.spec.key?("endpoint")
|
88
|
+
endpoint = @cls.spec["endpoint"]
|
89
|
+
else
|
90
|
+
endpoint = "/"+@cls.spec["object"]+"s"
|
91
|
+
end
|
92
|
+
|
93
|
+
if id
|
94
|
+
endpoint = File.join(endpoint, id)
|
95
|
+
end
|
96
|
+
|
97
|
+
url = URI.join(Payload::api_url, endpoint)
|
98
|
+
url.query = URI.encode_www_form(@filters)
|
99
|
+
|
100
|
+
http = Net::HTTP.new(url.host, url.port)
|
101
|
+
|
102
|
+
if url.port == 443
|
103
|
+
http.use_ssl = true
|
104
|
+
end
|
105
|
+
|
106
|
+
request = Net::HTTP.const_get(method).new(url.request_uri)
|
107
|
+
request.basic_auth(Payload::api_key, '')
|
108
|
+
|
109
|
+
if json
|
110
|
+
request.body = json.to_json
|
111
|
+
request.add_field('Content-Type', 'application/json')
|
112
|
+
end
|
113
|
+
|
114
|
+
response = http.request(request)
|
115
|
+
|
116
|
+
begin
|
117
|
+
data = JSON.parse(response.body)
|
118
|
+
rescue JSON::ParserError
|
119
|
+
if response.code == '500'
|
120
|
+
raise Payload::InternalError.new
|
121
|
+
else
|
122
|
+
raise Place::UnknownResponse.new
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
if response.code == '200'
|
127
|
+
if data['object'] == 'list'
|
128
|
+
return data['values'].map {|obj| Payload::get_cls(obj).new(obj) }
|
129
|
+
else
|
130
|
+
return Payload::get_cls(data).new(data)
|
131
|
+
end
|
132
|
+
else
|
133
|
+
for error in Payload::subclasses(Payload::PayloadError)
|
134
|
+
if error.code != response.code or error.name.split('::')[-1] != data['error_type']
|
135
|
+
next
|
136
|
+
end
|
137
|
+
|
138
|
+
raise error.new(data['description'], data)
|
139
|
+
end
|
140
|
+
|
141
|
+
raise Payload::BadRequest.new(data['description'], data)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Payload
|
2
|
+
class PayloadError < StandardError
|
3
|
+
@code = nil
|
4
|
+
class << self
|
5
|
+
attr_reader :code
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(msg, details = nil)
|
9
|
+
super(msg)
|
10
|
+
@details = details
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class UnknownResponse < PayloadError
|
15
|
+
end
|
16
|
+
|
17
|
+
class BadRequest < PayloadError
|
18
|
+
@code='400'
|
19
|
+
end
|
20
|
+
|
21
|
+
class InvalidAttributes < PayloadError
|
22
|
+
@code='400'
|
23
|
+
end
|
24
|
+
|
25
|
+
class Unauthorized < PayloadError
|
26
|
+
@code='401'
|
27
|
+
end
|
28
|
+
|
29
|
+
class Forbidden < PayloadError
|
30
|
+
@code='403'
|
31
|
+
end
|
32
|
+
|
33
|
+
class NotFound < PayloadError
|
34
|
+
@code='404'
|
35
|
+
end
|
36
|
+
|
37
|
+
class TooManyRequests < PayloadError
|
38
|
+
@code='429'
|
39
|
+
end
|
40
|
+
|
41
|
+
class InternalServerError < PayloadError
|
42
|
+
@code='500'
|
43
|
+
end
|
44
|
+
|
45
|
+
class ServiceUnavailable < PayloadError
|
46
|
+
@code='503'
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require "payload/arm/object"
|
2
|
+
|
3
|
+
module Payload
|
4
|
+
class Account < ARMObject
|
5
|
+
@spec = { 'object' => 'account' }
|
6
|
+
end
|
7
|
+
|
8
|
+
class Customer < ARMObject
|
9
|
+
@spec = { 'object' => 'account' }
|
10
|
+
@poly = { 'type' => 'customer' }
|
11
|
+
end
|
12
|
+
|
13
|
+
class ProcessingAccount < ARMObject
|
14
|
+
@spec = { 'object' => 'account' }
|
15
|
+
@poly = { 'type' => 'processing' }
|
16
|
+
end
|
17
|
+
|
18
|
+
class Org < ARMObject
|
19
|
+
@spec = { 'object' => 'org', 'endoint' => '/account/orgs' }
|
20
|
+
end
|
21
|
+
|
22
|
+
class Transaction < ARMObject
|
23
|
+
@spec = { 'object' => 'transaction' }
|
24
|
+
end
|
25
|
+
|
26
|
+
class Payment < ARMObject
|
27
|
+
@spec = { 'object' => 'transaction' }
|
28
|
+
@poly = { 'type' => 'payment' }
|
29
|
+
end
|
30
|
+
|
31
|
+
class Refund < ARMObject
|
32
|
+
@spec = { 'object' => 'transaction' }
|
33
|
+
@poly = { 'type' => 'refund' }
|
34
|
+
end
|
35
|
+
|
36
|
+
class Ledger < ARMObject
|
37
|
+
@spec = { 'object' => 'transaction_ledger' }
|
38
|
+
end
|
39
|
+
|
40
|
+
class PaymentMethod < ARMObject
|
41
|
+
@spec = { 'object' => 'payment_method' }
|
42
|
+
end
|
43
|
+
|
44
|
+
class Card < ARMObject
|
45
|
+
@spec = { 'object' => 'payment_method' }
|
46
|
+
@poly = { 'type' => 'card' }
|
47
|
+
end
|
48
|
+
|
49
|
+
class BankAccount < ARMObject
|
50
|
+
@spec = { 'object' => 'payment_method' }
|
51
|
+
@poly = { 'type' => 'bank_account' }
|
52
|
+
end
|
53
|
+
|
54
|
+
class BillingSchedule < ARMObject
|
55
|
+
@spec = { 'object' => 'billing_schedule' }
|
56
|
+
end
|
57
|
+
|
58
|
+
class BillingCharge < ARMObject
|
59
|
+
@spec = { 'object' => 'billing_charge' }
|
60
|
+
end
|
61
|
+
|
62
|
+
class Invoice < ARMObject
|
63
|
+
@spec = { 'object' => 'invoice' }
|
64
|
+
end
|
65
|
+
|
66
|
+
class LineItem < ARMObject
|
67
|
+
@spec = { 'object' => 'line_item' }
|
68
|
+
end
|
69
|
+
|
70
|
+
class ChargeItem < ARMObject
|
71
|
+
@spec = { 'object' => 'line_item' }
|
72
|
+
@poly = { 'type' => 'charge' }
|
73
|
+
end
|
74
|
+
|
75
|
+
class PaymentItem < ARMObject
|
76
|
+
@spec = { 'object' => 'line_item' }
|
77
|
+
@poly = { 'type' => 'payment' }
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Payload
|
2
|
+
|
3
|
+
def self.subclasses(super_cls)
|
4
|
+
ObjectSpace.each_object(Class).select { |cls| cls < super_cls }
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.get_cls(data)
|
8
|
+
match = nil
|
9
|
+
for cls in subclasses(Payload::ARMObject)
|
10
|
+
if cls.spec['object'] != data['object']
|
11
|
+
next
|
12
|
+
end
|
13
|
+
|
14
|
+
if not cls.poly and not match
|
15
|
+
match = cls
|
16
|
+
|
17
|
+
elsif cls.poly
|
18
|
+
|
19
|
+
invalid = false
|
20
|
+
cls.poly.each do |key, value|
|
21
|
+
if data[key] != value
|
22
|
+
invalid = true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
if invalid
|
27
|
+
next
|
28
|
+
end
|
29
|
+
|
30
|
+
match = cls
|
31
|
+
break
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
match
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
data/lib/payload/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: payload-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Payload
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-05-05 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A simple library to interface with the Payload API. See https://docs.payload.co
|
14
14
|
for details.
|
@@ -20,6 +20,11 @@ files:
|
|
20
20
|
- LICENSE
|
21
21
|
- README.md
|
22
22
|
- lib/payload.rb
|
23
|
+
- lib/payload/arm/object.rb
|
24
|
+
- lib/payload/arm/request.rb
|
25
|
+
- lib/payload/exceptions.rb
|
26
|
+
- lib/payload/objects.rb
|
27
|
+
- lib/payload/utils.rb
|
23
28
|
- lib/payload/version.rb
|
24
29
|
- payload.gemspec
|
25
30
|
homepage: https://docs.payload.co
|
@@ -41,8 +46,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
41
46
|
- !ruby/object:Gem::Version
|
42
47
|
version: '0'
|
43
48
|
requirements: []
|
44
|
-
|
45
|
-
rubygems_version: 2.7.7
|
49
|
+
rubygems_version: 3.0.1
|
46
50
|
signing_key:
|
47
51
|
specification_version: 4
|
48
52
|
summary: Payload ruby library
|