Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.1.0-alpha.36"
".": "0.1.0-alpha.37"
}
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# Changelog

## 0.1.0-alpha.37 (2025-04-03)

Full Changelog: [v0.1.0-alpha.36...v0.1.0-alpha.37](https://github.com/orbcorp/orb-ruby/compare/v0.1.0-alpha.36...v0.1.0-alpha.37)

### Bug Fixes

* pre-release version string should match ruby, not semver conventions ([#217](https://github.com/orbcorp/orb-ruby/issues/217)) ([a625486](https://github.com/orbcorp/orb-ruby/commit/a625486906ad75706e32c1c0542be9dafe9a8934))


### Chores

* demonstrate how to make undocumented requests in README ([#216](https://github.com/orbcorp/orb-ruby/issues/216)) ([fb65338](https://github.com/orbcorp/orb-ruby/commit/fb65338138069e09385b7d8f0f21eab810c39b91))
* **internal:** codegen related update ([#214](https://github.com/orbcorp/orb-ruby/issues/214)) ([3c5cd96](https://github.com/orbcorp/orb-ruby/commit/3c5cd96ec0ef0d725e327d40979456c0dea9b434))
* **internal:** codegen related update ([#215](https://github.com/orbcorp/orb-ruby/issues/215)) ([a7b225e](https://github.com/orbcorp/orb-ruby/commit/a7b225e091e967479f57ec0ba956d39e1fedb367))
* **internal:** version bump ([#211](https://github.com/orbcorp/orb-ruby/issues/211)) ([7c53448](https://github.com/orbcorp/orb-ruby/commit/7c53448564312f3fb638811f826366fcc267caa5))
* move private classes into internal module ([#213](https://github.com/orbcorp/orb-ruby/issues/213)) ([9217e7b](https://github.com/orbcorp/orb-ruby/commit/9217e7bff4eb522d63dde18e65ee5075ba851ab7))

## 0.1.0-alpha.36 (2025-04-02)

Full Changelog: [v0.1.0-alpha.35...v0.1.0-alpha.36](https://github.com/orbcorp/orb-ruby/compare/v0.1.0-alpha.35...v0.1.0-alpha.36)
Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ GIT
PATH
remote: .
specs:
orb-billing (0.1.0.pre.alpha.35)
orb-billing (0.1.0.pre.alpha.36)
connection_pool

GEM
Expand Down
35 changes: 31 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Orb Ruby API library

The Orb Ruby library provides convenient access to the Orb REST API from any Ruby 3.0.0+ application.
The Orb Ruby library provides convenient access to the Orb REST API from any Ruby 3.1.0+ application.

## Documentation

Expand All @@ -13,7 +13,7 @@ The underlying REST API documentation can be found on [docs.withorb.com](https:/
To use this gem, install via Bundler by adding the following to your application's `Gemfile`:

```ruby
gem "orb-billing", "~> 0.1.0.pre.alpha.35"
gem "orb-billing", "~> 0.1.0.pre.alpha.36"
```

To fetch an initial copy of the gem:
Expand Down Expand Up @@ -128,7 +128,9 @@ orb.customers.create(
)
```

## Sorbet Support
## LSP Support

### Sorbet

**This library emits an intentional warning under the [`tapioca` toolchain](https://github.com/Shopify/tapioca)**. This is normal, and does not impact functionality.

Expand All @@ -148,6 +150,31 @@ orb.customers.create(**model)

## Advanced

### Making custom/undocumented requests

This library is typed for convenient access to the documented API.

If you need to access undocumented endpoints, params, or response properties, the library can still be used.

#### Undocumented request params

If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` under the `request_options:` parameter when making a requests as seen in examples above.

#### Undocumented endpoints

To make requests to undocumented endpoints, you can make requests using `client.request`. Options on the client will be respected (such as retries) when making this request.

```ruby
response =
client.request(
method: :post,
path: '/undocumented/endpoint',
query: {"dog": "woof"},
headers: {"useful-header": "interesting-value"},
body: {"he": "llo"},
)
```

### Concurrency & Connection Pooling

The `Orb::Client` instances are thread-safe, and should be re-used across multiple threads. By default, each `Client` have their own HTTP connection pool, with a maximum number of connections equal to thread count.
Expand All @@ -166,4 +193,4 @@ This package considers improvements to the (non-runtime) `*.rbi` and `*.rbs` typ

## Requirements

Ruby 3.0.0 or higher.
Ruby 3.1.0 or higher.
30 changes: 15 additions & 15 deletions lib/orb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,24 @@

# Package files.
require_relative "orb/version"
require_relative "orb/util"
require_relative "orb/type/converter"
require_relative "orb/type/unknown"
require_relative "orb/type/boolean_model"
require_relative "orb/type/enum"
require_relative "orb/type/union"
require_relative "orb/type/array_of"
require_relative "orb/type/hash_of"
require_relative "orb/type/base_model"
require_relative "orb/type/base_page"
require_relative "orb/type/request_parameters"
require_relative "orb/type"
require_relative "orb/internal/util"
require_relative "orb/internal/type/converter"
require_relative "orb/internal/type/unknown"
require_relative "orb/internal/type/boolean_model"
require_relative "orb/internal/type/enum"
require_relative "orb/internal/type/union"
require_relative "orb/internal/type/array_of"
require_relative "orb/internal/type/hash_of"
require_relative "orb/internal/type/base_model"
require_relative "orb/internal/type/base_page"
require_relative "orb/internal/type/request_parameters"
require_relative "orb/internal"
require_relative "orb/request_options"
require_relative "orb/errors"
require_relative "orb/transport/base_client"
require_relative "orb/transport/pooled_net_requester"
require_relative "orb/internal/transport/base_client"
require_relative "orb/internal/transport/pooled_net_requester"
require_relative "orb/client"
require_relative "orb/page"
require_relative "orb/internal/page"
require_relative "orb/models/alert"
require_relative "orb/models/alert_create_for_customer_params"
require_relative "orb/models/alert_create_for_external_customer_params"
Expand Down
2 changes: 1 addition & 1 deletion lib/orb/client.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

module Orb
class Client < Orb::Transport::BaseClient
class Client < Orb::Internal::Transport::BaseClient
# Default max number of retries to attempt after a failed retryable request.
DEFAULT_MAX_RETRIES = 2

Expand Down
54 changes: 1 addition & 53 deletions lib/orb/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class APIStatusError < Orb::Errors::APIError
#
# @return [Orb::Errors::APIStatusError]
def self.for(url:, status:, body:, request:, response:, message: nil)
key = Orb::Util.dig(body, :type)
key = Orb::Internal::Util.dig(body, :type)
kwargs = {
url: url,
status: status,
Expand Down Expand Up @@ -262,56 +262,4 @@ class OrbInternalServerError < Orb::Errors::InternalServerError
TYPE = "https://docs.withorb.com/reference/error-responses#500-internal-server-error"
end
end

Error = Orb::Errors::Error

ConversionError = Orb::Errors::ConversionError

APIError = Orb::Errors::APIError

APIStatusError = Orb::Errors::APIStatusError

APIConnectionError = Orb::Errors::APIConnectionError

APITimeoutError = Orb::Errors::APITimeoutError

BadRequestError = Orb::Errors::BadRequestError

AuthenticationError = Orb::Errors::AuthenticationError

PermissionDeniedError = Orb::Errors::PermissionDeniedError

NotFoundError = Orb::Errors::NotFoundError

ConflictError = Orb::Errors::ConflictError

UnprocessableEntityError = Orb::Errors::UnprocessableEntityError

RateLimitError = Orb::Errors::RateLimitError

InternalServerError = Orb::Errors::InternalServerError

ConstraintViolation = Orb::Errors::ConstraintViolation

DuplicateResourceCreation = Orb::Errors::DuplicateResourceCreation

FeatureNotAvailable = Orb::Errors::FeatureNotAvailable

RequestValidationError = Orb::Errors::RequestValidationError

OrbAuthenticationError = Orb::Errors::OrbAuthenticationError

ResourceNotFound = Orb::Errors::ResourceNotFound

URLNotFound = Orb::Errors::URLNotFound

ResourceConflict = Orb::Errors::ResourceConflict

RequestTooLarge = Orb::Errors::RequestTooLarge

ResourceTooLarge = Orb::Errors::ResourceTooLarge

TooManyRequests = Orb::Errors::TooManyRequests

OrbInternalServerError = Orb::Errors::OrbInternalServerError
end
8 changes: 8 additions & 0 deletions lib/orb/internal.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

module Orb
# @api private
module Internal
OMIT = Object.new.freeze
end
end
108 changes: 108 additions & 0 deletions lib/orb/internal/page.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# frozen_string_literal: true

module Orb
module Internal
# @example
# if page.has_next?
# page = page.next_page
# end
#
# @example
# page.auto_paging_each do |coupon|
# puts(coupon)
# end
class Page
include Orb::Internal::Type::BasePage

# @return [Array<Object>, nil]
attr_accessor :data

# @return [PaginationMetadata]
attr_accessor :pagination_metadata

# @api private
#
# @param client [Orb::Internal::Transport::BaseClient]
# @param req [Hash{Symbol=>Object}]
# @param headers [Hash{String=>String}, Net::HTTPHeader]
# @param page_data [Hash{Symbol=>Object}]
def initialize(client:, req:, headers:, page_data:)
super
model = req.fetch(:model)

case page_data
in {data: Array | nil => data}
@data = data&.map { Orb::Internal::Type::Converter.coerce(model, _1) }
else
end

case page_data
in {pagination_metadata: Hash | nil => pagination_metadata}
@pagination_metadata =
Orb::Internal::Type::Converter.coerce(
Orb::Internal::Page::PaginationMetadata,
pagination_metadata
)
else
end
end

# @return [Boolean]
def next_page?
!pagination_metadata&.next_cursor.nil?
end

# @raise [Orb::HTTP::Error]
# @return [Orb::Internal::Page]
def next_page
unless next_page?
message = "No more pages available. Please check #next_page? before calling ##{__method__}"
raise RuntimeError.new(message)
end

req = Orb::Internal::Util.deep_merge(@req, {query: {cursor: pagination_metadata&.next_cursor}})
@client.request(req)
end

# @param blk [Proc]
def auto_paging_each(&blk)
unless block_given?
raise ArgumentError.new("A block must be given to ##{__method__}")
end
page = self
loop do
page.data&.each { blk.call(_1) }
break unless page.next_page?
page = page.next_page
end
end

# @return [String]
def inspect
# rubocop:disable Layout/LineLength
"#<#{self.class}:0x#{object_id.to_s(16)} data=#{data.inspect} pagination_metadata=#{pagination_metadata.inspect}>"
# rubocop:enable Layout/LineLength
end

class PaginationMetadata < Orb::Internal::Type::BaseModel
# @!attribute has_more
#
# @return [Boolean]
required :has_more, Orb::Internal::Type::BooleanModel

# @!attribute next_cursor
#
# @return [String, nil]
required :next_cursor, String, nil?: true

# @!parse
# # @param has_more [Boolean]
# # @param next_cursor [String, nil]
# #
# def initialize(has_more:, next_cursor:, **) = super

# def initialize: (Hash | Orb::Internal::Type::BaseModel) -> void
end
end
end
end
Loading
Loading