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 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.
@@ -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
@@ -0,0 +1,5 @@
1
+ module Bizowie
2
+ class API
3
+ VERSION = '0.5.0'.freeze
4
+ end
5
+ end
@@ -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: []