bizowie-api 0.5.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 +7 -0
- data/README.md +126 -0
- data/bizowie-api.gemspec +25 -0
- data/lib/bizowie/api/response.rb +19 -0
- data/lib/bizowie/api/version.rb +5 -0
- data/lib/bizowie/api.rb +142 -0
- metadata +53 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: cd5c5425932023526bd9d2f1a1c52907686d3b42a5aa1c9e610950d50ebd037c
|
|
4
|
+
data.tar.gz: 5e9d369dff684e4fc65a260881940b1be5366df1c1e5991dfcf95a37eeda50dc
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: d67e5d2553436eb96c92eeacf03beed406298e0d9f1945ac1e4b97b644adeb50b77e2cd25518fd805c1fe9ec5371aeb6ffaf6ade5f7f0cdd6a903d9f0f6ff85d
|
|
7
|
+
data.tar.gz: a44c36b0dd2fdee3182cfe0b68d92e0fa665b482ae441859668da17e7e1b865154b37d6aacd9b52eaa036bc5a730384f1bafb6a07b46c34296206ee55a827552
|
data/README.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# bizowie-api (Ruby)
|
|
2
|
+
|
|
3
|
+
Ruby client for [Bizowie's](https://bizowie.com) ERP API. Port of the Perl
|
|
4
|
+
[`WWW::Bizowie::API`](https://github.com/bizowie/WWW-Bizowie-API) module.
|
|
5
|
+
|
|
6
|
+
- Zero runtime dependencies (only Ruby stdlib: `net/http`, `json`)
|
|
7
|
+
- Supports both the v1 and v2 API endpoints
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
- Ruby **2.7 or newer**
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
Add to your `Gemfile`:
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
gem 'bizowie-api'
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or install directly:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
gem install bizowie-api
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick start
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
require 'bizowie/api'
|
|
31
|
+
|
|
32
|
+
bz = Bizowie::API.new(
|
|
33
|
+
api_key: '02cc7058-cd22-4c8e-ad7c-a8f3f2a64bd0',
|
|
34
|
+
secret_key: '58c57abc-1e16-3571-bb35-73876bcef746',
|
|
35
|
+
site: 'mysite.bizowie.com',
|
|
36
|
+
v2: true, # recommended for new integrations
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
res = bz.call('databases/add_note/3/10/123', comment: 'hello from Ruby')
|
|
40
|
+
|
|
41
|
+
if res.success == 1
|
|
42
|
+
puts "ok: #{res.data.inspect}"
|
|
43
|
+
else
|
|
44
|
+
warn "failed: #{res.data.inspect}"
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## API
|
|
49
|
+
|
|
50
|
+
### `Bizowie::API.new(**options)`
|
|
51
|
+
|
|
52
|
+
Creates a client instance. Raises `ArgumentError` if `site`, `api_key`, or
|
|
53
|
+
`secret_key` is missing.
|
|
54
|
+
|
|
55
|
+
| Option | Type | Required | Description |
|
|
56
|
+
| ------------- | --------- | -------- | ----------------------------------------------------------------------------- |
|
|
57
|
+
| `api_key` | `String` | yes | Your Bizowie API key. |
|
|
58
|
+
| `secret_key` | `String` | yes | Your Bizowie secret key. |
|
|
59
|
+
| `site` | `String` | yes | Hostname of your Bizowie instance (e.g. `mysite.bizowie.com`). |
|
|
60
|
+
| `v2` | `Boolean` | no | Route calls through the v2 endpoint (`/bz/apiv2/call/`). Recommended. |
|
|
61
|
+
| `api_version` | `String` | no | API version sent with each v2 request. Defaults to `'1.00'`. |
|
|
62
|
+
| `debug` | `Boolean` | no | Log the raw HTTP body to stderr when the response can't be parsed as JSON. |
|
|
63
|
+
|
|
64
|
+
### `client.call(method, params = nil)` → `Bizowie::API::Response`
|
|
65
|
+
|
|
66
|
+
Makes an API call.
|
|
67
|
+
|
|
68
|
+
- `method` — path to the API method (everything after `/bz/api/` for v1 or
|
|
69
|
+
`/bz/apiv2/call/` for v2). Raises if empty.
|
|
70
|
+
- `params` — `Hash` of parameters; JSON-encoded for you. May be omitted.
|
|
71
|
+
|
|
72
|
+
In v2 mode, `api_key`, `secret_key`, and `api_version` are injected
|
|
73
|
+
automatically — don't include them in `params`.
|
|
74
|
+
|
|
75
|
+
### `Bizowie::API::Response`
|
|
76
|
+
|
|
77
|
+
| Method | Returns | Description |
|
|
78
|
+
| --------- | --------- | ------------------------------------------------------------------------------------------------------------- |
|
|
79
|
+
| `success` | `Integer` | `1` on success, `0` otherwise. Pulled from the response body's `success` field. |
|
|
80
|
+
| `data` | `Hash` | Decoded JSON response (with `success` removed). On a non-JSON response this is `{ 'unprocessed' => 1 }`. |
|
|
81
|
+
|
|
82
|
+
## Error handling
|
|
83
|
+
|
|
84
|
+
`call` does **not** raise on HTTP errors — application-level failures are
|
|
85
|
+
surfaced via `success: 0` and whatever the server returned in `data`. It
|
|
86
|
+
*does* raise on network-level failures (DNS, connection refused, TLS
|
|
87
|
+
errors), since those bubble up from `Net::HTTP`. Rescue if you want to
|
|
88
|
+
handle those distinctly:
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
begin
|
|
92
|
+
res = bz.call('some/method', foo: 'bar')
|
|
93
|
+
warn 'application-level failure' unless res.success == 1
|
|
94
|
+
rescue StandardError => e
|
|
95
|
+
warn "network/TLS failure: #{e.message}"
|
|
96
|
+
end
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
If the server returns non-JSON (e.g., an HTML error page), `res.success`
|
|
100
|
+
will be `0` and `res.data` will be `{ 'unprocessed' => 1 }`. Pass
|
|
101
|
+
`debug: true` to the constructor to log the raw body to stderr while
|
|
102
|
+
wiring things up.
|
|
103
|
+
|
|
104
|
+
## v1 vs v2
|
|
105
|
+
|
|
106
|
+
| Aspect | v1 (default) | v2 (`v2: true`) |
|
|
107
|
+
| --------------- | ------------------------------------------ | ------------------------------------------------ |
|
|
108
|
+
| Endpoint | `https://{site}/bz/api/{method}` | `https://{site}/bz/apiv2/call/{method}` |
|
|
109
|
+
| Auth | Sent as separate multipart form fields | Injected into the JSON request body |
|
|
110
|
+
| Body | `multipart/form-data` with a `request` JSON field | Raw JSON body with `Content-Type: form-data` |
|
|
111
|
+
| `api_version` | not sent | sent (defaults to `'1.00'`) |
|
|
112
|
+
|
|
113
|
+
v2 is recommended for new integrations.
|
|
114
|
+
|
|
115
|
+
## TLS verification
|
|
116
|
+
|
|
117
|
+
Unlike the Perl module, this client **does not disable TLS verification**.
|
|
118
|
+
If you need to talk to a host with a self-signed certificate (e.g., a dev
|
|
119
|
+
instance), the cleanest approach is to install the cert into your trust
|
|
120
|
+
store rather than to disable verification.
|
|
121
|
+
|
|
122
|
+
## License
|
|
123
|
+
|
|
124
|
+
Dual-licensed under the
|
|
125
|
+
[Artistic License 1.0](https://opensource.org/licenses/Artistic-1.0) or the
|
|
126
|
+
GPL 1.0+, matching the original Perl module.
|
data/bizowie-api.gemspec
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require_relative 'lib/bizowie/api/version'
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |spec|
|
|
4
|
+
spec.name = 'bizowie-api'
|
|
5
|
+
spec.version = Bizowie::API::VERSION
|
|
6
|
+
spec.authors = ['Bizowie']
|
|
7
|
+
spec.email = ['info@bizowie.com']
|
|
8
|
+
|
|
9
|
+
spec.summary = "Ruby client for Bizowie's ERP API."
|
|
10
|
+
spec.description = 'Ruby port of WWW::Bizowie::API. Provides a simple ' \
|
|
11
|
+
'client for the v1 and v2 Bizowie ERP API endpoints.'
|
|
12
|
+
spec.homepage = 'https://bizowie.com'
|
|
13
|
+
spec.licenses = ['Artistic-1.0-Perl', 'GPL-1.0-or-later']
|
|
14
|
+
|
|
15
|
+
spec.required_ruby_version = '>= 2.7'
|
|
16
|
+
|
|
17
|
+
spec.files = Dir['lib/**/*.rb'] + %w[README.md bizowie-api.gemspec]
|
|
18
|
+
spec.require_paths = ['lib']
|
|
19
|
+
|
|
20
|
+
spec.metadata = {
|
|
21
|
+
'homepage_uri' => 'https://bizowie.com',
|
|
22
|
+
'source_code_uri' => 'https://github.com/bizowie/WWW-Bizowie-API',
|
|
23
|
+
'bug_tracker_uri' => 'https://github.com/bizowie/WWW-Bizowie-API/issues',
|
|
24
|
+
}
|
|
25
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Bizowie
|
|
2
|
+
class API
|
|
3
|
+
# Response returned by {Bizowie::API#call}.
|
|
4
|
+
#
|
|
5
|
+
# @!attribute [r] data
|
|
6
|
+
# @return [Hash] Decoded JSON response body (with +success+ removed).
|
|
7
|
+
# +{ 'unprocessed' => 1 }+ if the body could not be parsed.
|
|
8
|
+
# @!attribute [r] success
|
|
9
|
+
# @return [Integer] +1+ on success, +0+ otherwise.
|
|
10
|
+
class Response
|
|
11
|
+
attr_reader :data, :success
|
|
12
|
+
|
|
13
|
+
def initialize(data:, success:)
|
|
14
|
+
@data = data
|
|
15
|
+
@success = success
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
data/lib/bizowie/api.rb
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'net/http'
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
require 'uri'
|
|
5
|
+
|
|
6
|
+
require_relative 'api/response'
|
|
7
|
+
require_relative 'api/version'
|
|
8
|
+
|
|
9
|
+
module Bizowie
|
|
10
|
+
# Ruby client for the Bizowie ERP API.
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# require 'bizowie/api'
|
|
14
|
+
#
|
|
15
|
+
# bz = Bizowie::API.new(
|
|
16
|
+
# api_key: '02cc7058-cd22-4c8e-ad7c-a8f3f2a64bd0',
|
|
17
|
+
# secret_key: '58c57abc-1e16-3571-bb35-73876bcef746',
|
|
18
|
+
# site: 'mysite.bizowie.com',
|
|
19
|
+
# v2: true,
|
|
20
|
+
# )
|
|
21
|
+
#
|
|
22
|
+
# res = bz.call('databases/add_note/3/10/123', comment: 'hello from Ruby')
|
|
23
|
+
# puts res.success
|
|
24
|
+
# puts res.data
|
|
25
|
+
class API
|
|
26
|
+
USER_AGENT = 'Bizowie::API'.freeze
|
|
27
|
+
|
|
28
|
+
# @param api_key [String] Your Bizowie API key.
|
|
29
|
+
# @param secret_key [String] Your Bizowie secret key.
|
|
30
|
+
# @param site [String] Hostname of your Bizowie instance (e.g. +mysite.bizowie.com+).
|
|
31
|
+
# @param v2 [Boolean] Route calls through the v2 endpoint. Recommended for new integrations.
|
|
32
|
+
# @param api_version [String, nil] API version sent with each v2 request. Defaults to +'1.00'+.
|
|
33
|
+
# @param debug [Boolean] When true, log the raw HTTP body to stderr if the response can't be parsed as JSON.
|
|
34
|
+
# @raise [ArgumentError] if +site+, +api_key+, or +secret_key+ is missing.
|
|
35
|
+
def initialize(api_key:, secret_key:, site:, v2: false, api_version: nil, debug: false)
|
|
36
|
+
raise ArgumentError, 'site not specified' if site.nil? || site.to_s.empty?
|
|
37
|
+
raise ArgumentError, 'api_key not specified' if api_key.nil? || api_key.to_s.empty?
|
|
38
|
+
raise ArgumentError, 'secret_key not specified' if secret_key.nil? || secret_key.to_s.empty?
|
|
39
|
+
|
|
40
|
+
@api_key = api_key
|
|
41
|
+
@secret_key = secret_key
|
|
42
|
+
@site = site
|
|
43
|
+
@v2 = v2
|
|
44
|
+
@api_version = api_version
|
|
45
|
+
@debug = debug
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Make an API call. Dispatches to the v1 or v2 endpoint based on the
|
|
49
|
+
# +v2+ option passed to the constructor.
|
|
50
|
+
#
|
|
51
|
+
# Does not raise on HTTP errors — application-level failures are surfaced
|
|
52
|
+
# via +success: 0+ on the returned response. Network-level failures (DNS,
|
|
53
|
+
# connection refused, TLS errors) bubble up from Net::HTTP.
|
|
54
|
+
#
|
|
55
|
+
# @param method [String] Path to the API method (everything after
|
|
56
|
+
# +/bz/api/+ for v1 or +/bz/apiv2/call/+ for v2).
|
|
57
|
+
# @param params [Hash, nil] Parameters to send. JSON-encoded for you.
|
|
58
|
+
# In v2 mode, +api_key+/+secret_key+/+api_version+ are injected
|
|
59
|
+
# automatically — don't include them here.
|
|
60
|
+
# @return [Bizowie::API::Response]
|
|
61
|
+
# @raise [RuntimeError] if +method+ is empty.
|
|
62
|
+
def call(method, params = nil)
|
|
63
|
+
@v2 ? call_v2(method, params) : call_v1(method, params)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def call_v1(method, params)
|
|
69
|
+
raise '[Bizowie::API] fatal error: no method given' if method.nil? || method.to_s.empty?
|
|
70
|
+
|
|
71
|
+
request_body = JSON.generate(params || {})
|
|
72
|
+
boundary = "----BizowieAPI#{SecureRandom.hex(16)}"
|
|
73
|
+
body = build_multipart(boundary,
|
|
74
|
+
'api_key' => @api_key,
|
|
75
|
+
'secret_key' => @secret_key,
|
|
76
|
+
'site' => @site,
|
|
77
|
+
'request' => request_body,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
response = http_post(
|
|
81
|
+
"https://#{@site}/bz/api/#{method}",
|
|
82
|
+
body,
|
|
83
|
+
'Content-Type' => "multipart/form-data; boundary=#{boundary}",
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
parse_response(response)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def call_v2(method, params)
|
|
90
|
+
raise '[Bizowie::API] fatal error: no method given' if method.nil? || method.to_s.empty?
|
|
91
|
+
|
|
92
|
+
payload = (params || {}).each_with_object({}) { |(k, v), h| h[k.to_s] = v }
|
|
93
|
+
payload['api_key'] = @api_key
|
|
94
|
+
payload['secret_key'] = @secret_key
|
|
95
|
+
payload['api_version'] = @api_version || '1.00' unless payload['api_version']
|
|
96
|
+
|
|
97
|
+
response = http_post(
|
|
98
|
+
"https://#{@site}/bz/apiv2/call/#{method}",
|
|
99
|
+
JSON.generate(payload),
|
|
100
|
+
'Content-Type' => 'form-data',
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
parse_response(response)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def http_post(url, body, headers)
|
|
107
|
+
uri = URI.parse(url)
|
|
108
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
109
|
+
http.use_ssl = (uri.scheme == 'https')
|
|
110
|
+
|
|
111
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
|
112
|
+
headers.each { |k, v| request[k] = v }
|
|
113
|
+
request['User-Agent'] = USER_AGENT
|
|
114
|
+
request.body = body
|
|
115
|
+
|
|
116
|
+
http.request(request)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def build_multipart(boundary, fields)
|
|
120
|
+
parts = fields.map do |name, value|
|
|
121
|
+
"--#{boundary}\r\n" \
|
|
122
|
+
"Content-Disposition: form-data; name=\"#{name}\"\r\n\r\n" \
|
|
123
|
+
"#{value}\r\n"
|
|
124
|
+
end
|
|
125
|
+
parts.join + "--#{boundary}--\r\n"
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def parse_response(response)
|
|
129
|
+
body = response.body.to_s
|
|
130
|
+
data =
|
|
131
|
+
begin
|
|
132
|
+
JSON.parse(body)
|
|
133
|
+
rescue JSON::ParserError
|
|
134
|
+
warn "[Bizowie::API] #{response.code} #{response.message}\n#{body}" if @debug
|
|
135
|
+
{ 'unprocessed' => 1 }
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
success = data.delete('success') || 0
|
|
139
|
+
Response.new(data: data, success: success)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: bizowie-api
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.5.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Bizowie
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-05-18 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Ruby port of WWW::Bizowie::API. Provides a simple client for the v1 and
|
|
14
|
+
v2 Bizowie ERP API endpoints.
|
|
15
|
+
email:
|
|
16
|
+
- info@bizowie.com
|
|
17
|
+
executables: []
|
|
18
|
+
extensions: []
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- README.md
|
|
22
|
+
- bizowie-api.gemspec
|
|
23
|
+
- lib/bizowie/api.rb
|
|
24
|
+
- lib/bizowie/api/response.rb
|
|
25
|
+
- lib/bizowie/api/version.rb
|
|
26
|
+
homepage: https://bizowie.com
|
|
27
|
+
licenses:
|
|
28
|
+
- Artistic-1.0-Perl
|
|
29
|
+
- GPL-1.0-or-later
|
|
30
|
+
metadata:
|
|
31
|
+
homepage_uri: https://bizowie.com
|
|
32
|
+
source_code_uri: https://github.com/bizowie/WWW-Bizowie-API
|
|
33
|
+
bug_tracker_uri: https://github.com/bizowie/WWW-Bizowie-API/issues
|
|
34
|
+
post_install_message:
|
|
35
|
+
rdoc_options: []
|
|
36
|
+
require_paths:
|
|
37
|
+
- lib
|
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
39
|
+
requirements:
|
|
40
|
+
- - ">="
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: '2.7'
|
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
requirements: []
|
|
49
|
+
rubygems_version: 3.4.20
|
|
50
|
+
signing_key:
|
|
51
|
+
specification_version: 4
|
|
52
|
+
summary: Ruby client for Bizowie's ERP API.
|
|
53
|
+
test_files: []
|