Class: Sdp::Client
- Inherits:
-
Object
- Object
- Sdp::Client
- Defined in:
- lib/sdp/client.rb
Overview
Zero-dependency Net::HTTP request core for the SDP API.
Success envelope: { “data”: …, “meta”: … } Error envelope: { “error”: { “code”, “message”, “details” }, “meta”: … }
Retry policy: GETs retry once on Timeout/Unavailable. POSTs NEVER retry —SDP has no idempotency key, so re-sending a transfer risks a double-spend.
Endpoint methods live in resource modules layered on top of the #get/#post primitives below; this class owns auth, envelope handling, the typed error mapping, and the retry posture.
Defined Under Namespace
Classes: Response
Constant Summary collapse
- DEFAULT_BASE_URL =
"http://127.0.0.1:8787"- OPEN_TIMEOUT =
seconds — fail fast when the stack isn’t up
2- READ_TIMEOUT =
seconds — transfer confirmation is synchronous
10- NOT_FOUND_HINT =
Wallet-scoped API keys return 404 (not 403) for wallets outside their scope, which reads like “does not exist” when it really means “not yours”. Appended to every NotFound so the failure is diagnosable.
"(hint: wallet-scoped API keys return 404 for wallets outside their scope)"
Instance Attribute Summary collapse
-
#base_url ⇒ Object
readonly
Returns the value of attribute base_url.
-
#custody_provider ⇒ Object
readonly
Returns the value of attribute custody_provider.
Instance Method Summary collapse
-
#get(path, query: nil) ⇒ Object
Reads are safe to retry exactly once on transport-level failures.
-
#initialize(base_url: ENV.fetch("SDP_API_BASE_URL", DEFAULT_BASE_URL), api_key: ENV["SDP_API_KEY"], custody_provider: ENV["SDP_CUSTODY_PROVIDER"], open_timeout: OPEN_TIMEOUT, read_timeout: READ_TIMEOUT) ⇒ Client
constructor
A new instance of Client.
-
#inspect ⇒ Object
Redacted on purpose: the API key is a bearer secret and must never leak into consoles, logs, or exception-capture payloads via the default #inspect (which would dump every instance variable, @api_key included).
- #post(path, payload = nil) ⇒ Object
Methods included from Resources::Ramps
#offramp_currencies, #offramp_execute, #onramp_currencies, #onramp_execute, #onramp_quote, #simulate_ramp
Methods included from Resources::Issuance
#burn_token, #create_token, #deploy_token, #get_token, #list_tokens, #mint_token, #prepare_burn_token, #prepare_deploy_token, #prepare_mint_token
Methods included from Resources::Payments
#create_transfer, #get_transfer, #list_transfers, #prepare_transfer
Methods included from Resources::Wallets
#create_wallet, #initialize_custody, #list_wallets, #wallet_balances
Constructor Details
#initialize(base_url: ENV.fetch("SDP_API_BASE_URL", DEFAULT_BASE_URL), api_key: ENV["SDP_API_KEY"], custody_provider: ENV["SDP_CUSTODY_PROVIDER"], open_timeout: OPEN_TIMEOUT, read_timeout: READ_TIMEOUT) ⇒ Client
Returns a new instance of Client.
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/sdp/client.rb', line 50 def initialize(base_url: ENV.fetch("SDP_API_BASE_URL", DEFAULT_BASE_URL), api_key: ENV["SDP_API_KEY"], custody_provider: ENV["SDP_CUSTODY_PROVIDER"], open_timeout: OPEN_TIMEOUT, read_timeout: READ_TIMEOUT) # Strip first, then guard: an ENV key with a trailing newline passes a # naive blank-check but then makes every request raise a raw ArgumentError # from the "Bearer …\n" header. Normalize once, at the boundary. @api_key = api_key.to_s.strip if @api_key.empty? raise ConfigurationError, "SDP_API_KEY is missing or blank. " \ "Pass api_key: or set the SDP_API_KEY environment variable." end @base_url = base_url.to_s.chomp("/") # base_url is documented as ConfigurationError-covered, so validate it at # boot (mirroring the api_key fail-fast) instead of letting an unusable # URL surface as a cryptic transport error on the first request. parsed = begin URI.parse(@base_url) rescue URI::InvalidURIError nil end unless parsed.is_a?(URI::HTTP) && !parsed.host.to_s.empty? raise ConfigurationError, "SDP_API_BASE_URL is invalid: expected an http(s) URL with a " \ "host, got #{@base_url.inspect}. Pass base_url: or set the SDP_API_BASE_URL environment variable." end # The default custody provider for wallet operations, configured once here # (or via SDP_CUSTODY_PROVIDER) so callers don't repeat provider: on every # create_wallet/initialize_custody. Blank → nil (fall through to SDP's own # default). This is what makes the ProviderCapabilityError hint actionable. provider = custody_provider.to_s.strip @custody_provider = provider.empty? ? nil : provider @open_timeout = open_timeout @read_timeout = read_timeout end |
Instance Attribute Details
#base_url ⇒ Object (readonly)
Returns the value of attribute base_url.
48 49 50 |
# File 'lib/sdp/client.rb', line 48 def base_url @base_url end |
#custody_provider ⇒ Object (readonly)
Returns the value of attribute custody_provider.
48 49 50 |
# File 'lib/sdp/client.rb', line 48 def custody_provider @custody_provider end |
Instance Method Details
#get(path, query: nil) ⇒ Object
Reads are safe to retry exactly once on transport-level failures.
101 102 103 104 105 106 |
# File 'lib/sdp/client.rb', line 101 def get(path, query: nil) uri = build_uri(path, query) with_read_retry do perform(Net::HTTP::Get.new(uri), uri, idempotent: true) end end |
#inspect ⇒ Object
Redacted on purpose: the API key is a bearer secret and must never leak into consoles, logs, or exception-capture payloads via the default #inspect (which would dump every instance variable, @api_key included).
92 93 94 |
# File 'lib/sdp/client.rb', line 92 def inspect "#<#{self.class} base_url=#{@base_url.inspect}>" end |
#post(path, payload = nil) ⇒ Object
108 109 110 111 112 113 114 |
# File 'lib/sdp/client.rb', line 108 def post(path, payload = nil) uri = build_uri(path, nil) request = Net::HTTP::Post.new(uri) request["Content-Type"] = "application/json" request.body = JSON.generate(payload) unless payload.nil? perform(request, uri, idempotent: false) # no retry wrapper — writes are never retried end |