Skip to content

feat: accept custom reqwest::Client via Config#321

Open
skyc1e wants to merge 2 commits intoPolymarket:mainfrom
skyc1e:feat/custom-http-client
Open

feat: accept custom reqwest::Client via Config#321
skyc1e wants to merge 2 commits intoPolymarket:mainfrom
skyc1e:feat/custom-http-client

Conversation

@skyc1e
Copy link
Copy Markdown

@skyc1e skyc1e commented Apr 7, 2026

Closes #308

Summary

Adds an optional http_client field to Config so callers can inject a pre-configured reqwest::Client.

Motivation

The internal reqwest::Client is built with minimal defaults, which leaves performance on the table for latency-sensitive use cases (market making, automated trading). Users currently have no way to tune TCP_NODELAY, connection pool sizing, HTTP/2 window parameters, keep-alive, proxies, or TLS settings.

Rather than expose individual knobs in Config (which would grow over time and mirror reqwest::ClientBuilder), this PR lets callers bring their own fully-configured client.

Changes

  • Config::http_client — new Option<reqwest::Client> field (default None)
  • Client::new — when http_client is Some, uses it directly; otherwise builds the default client as before
  • Testcustom_http_client_should_be_used verifies the custom client path works end-to-end

Backward compatibility

Fully backward compatible. Config::default() and all existing builder calls continue to work unchanged — http_client defaults to None.

Usage

let custom = reqwest::Client::builder()
    .tcp_nodelay(true)
    .pool_max_idle_per_host(10)
    .http2_initial_stream_window_size(524_288)
    .tcp_keepalive(Duration::from_secs(30))
    .default_headers(/* ... */)
    .build()?;

let config = Config::builder()
    .http_client(custom)
    .build();

let client = Client::new("https://clob.polymarket.com", config)?;

Note

Medium Risk
Moderate risk: changes client construction to optionally use a caller-supplied reqwest::Client and tweaks the cancel_order request body field name, which could affect cancellation behavior if the API expects the prior key or if callers provide clients with missing default headers/timeouts.

Overview
Adds HTTP client injection via config. Config now includes an optional http_client: Option<reqwest::Client>; Client::new uses the provided client as-is or falls back to building the default client with standard headers.

Adjusts cancel order request payload. cancel_order now sends { "orderID": ... } instead of { "orderId": ... }, and tests are updated accordingly. A new test (custom_http_client_should_be_used) validates the custom-client path end-to-end.

Reviewed by Cursor Bugbot for commit 90fb110. Bugbot is set up for automated code reviews on this repo. Configure here.

skyc1e added 2 commits April 7, 2026 00:38
The cancel_order method was sending `orderId` (camelCase) but the CLOB API
expects `orderID` (capital D), matching the TypeScript and Python clients.
The mock test was also using the wrong key, masking the issue.
Add an optional `http_client` field to `Config` so that callers can
inject a pre-configured `reqwest::Client`.  This addresses the need
for fine-grained HTTP tuning (TCP_NODELAY, connection pool sizing,
HTTP/2 windows, keep-alive, proxies, TLS) without expanding the
library's own configuration surface.

When `http_client` is `None` (the default), behavior is unchanged.

Closes Polymarket#308
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 90fb110. Configure here.

Comment thread src/clob/client.rs
let client = match config.http_client.clone() {
Some(custom) => custom,
None => ReqwestClient::builder().default_headers(headers).build()?,
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default headers built but unused with custom client

Low Severity

The headers HeaderMap is unconditionally constructed and populated with four entries (User-Agent, Accept, Connection, Content-Type), but when config.http_client is Some, the headers variable is never used. The header construction belongs inside the None arm of the match so it's only performed when actually needed.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 90fb110. Configure here.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 7, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.55%. Comparing base (77264a4) to head (90fb110).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #321   +/-   ##
=======================================
  Coverage   85.54%   85.55%           
=======================================
  Files          32       32           
  Lines        5167     5170    +3     
=======================================
+ Hits         4420     4423    +3     
  Misses        747      747           
Flag Coverage Δ
rust 85.55% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Zorak556 added a commit to Zorak556/polymarket-client-sdk that referenced this pull request Apr 10, 2026
Upstream merges:
- Polymarket#321: accept custom reqwest::Client via Config
- Polymarket#322: BuilderTradeResponse.builder Address → ApiKey
- Polymarket#306: add match_time_nano to TradeResponse
- Polymarket#305: preserve unknown activity side values
- Polymarket#303: version bump to 0.4.5
- Dep bumps: rust_decimal 1.41, uuid 1.23

Local patches:
- Reduce auth header allocations (HeaderValue::from for integers)
- Reorder order_builder size validation before async fee_rate call
- Skip double deserialization when tracing is disabled
- subscribe_book_and_prices: single-stream book + price_change
- subscribe_user/orders/trades: async for tokio::sync::RwLock
- Subscription lag: escalate to error and force resubscribe
- Broadcast capacity: 1024 → 16384
- excludeDepositsWithdrawals param on ActivityRequest
- cancel_order: orderId → orderID

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Zorak556 added a commit to Zorak556/polymarket-client-sdk that referenced this pull request Apr 10, 2026
Upstream merges:
- Polymarket#321: accept custom reqwest::Client via Config
- Polymarket#322: BuilderTradeResponse.builder Address → ApiKey
- Polymarket#306: add match_time_nano to TradeResponse
- Polymarket#305: preserve unknown activity side values
- Polymarket#303: version bump to 0.4.5
- Dep bumps: rust_decimal 1.41, uuid 1.23

Local patches:
- Reduce auth header allocations (HeaderValue::from for integers)
- Reorder order_builder size validation before async fee_rate call
- Skip double deserialization when tracing is disabled
- subscribe_book_and_prices: single-stream book + price_change
- subscribe_user/orders/trades: async for tokio::sync::RwLock
- Subscription lag: escalate to error and force resubscribe
- Broadcast capacity: 1024 → 16384
- excludeDepositsWithdrawals param on ActivityRequest
- cancel_order: orderId → orderID

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow custom reqwest::Client or expose HTTP client configuration

1 participant