Skip to content

feat(client): expose the resolved endpoint on rest and websocket clients - #12

Merged
kevinypfan merged 1 commit into
release/v1.5.0from
feat/expose-resolved-url
Aug 4, 2026
Merged

feat(client): expose the resolved endpoint on rest and websocket clients#12
kevinypfan merged 1 commit into
release/v1.5.0from
feat/expose-resolved-url

Conversation

@kevinypfan

Copy link
Copy Markdown
Collaborator

為什麼需要這個

rc4 把 baseUrl 收斂成「只決定 host / path prefix」之後,版本段改由 SDK 決定。這是對的分工,但它拿走了使用者原本自然擁有的資訊——以前版本是他自己寫進 URL 的,現在他問不出「我實際上跑在哪個版本」。

而且完全沒有出口:RestClientWebSocketClient 的建構子都是 protected readonly options,連我們自己的測試都得靠 @ts-ignore 才讀得到:

// @ts-ignore - accessing private property for testing
stock.options.url

當測試需要繞過型別系統才能驗證行為,那通常表示缺的是公開 API,不是測試寫法有問題。

加了什麼

回傳
WebSocketClient.url 完整 endpoint,含版本段與 /streaming
RestClient.baseUrl 請求組裝的 prefix,含版本段與 product
const client = new WebSocketClient({ apiKey, baseUrl: 'wss://fubon-api.fugle.tw/marketdata' });
client.futopt.url  // wss://fubon-api.fugle.tw/marketdata/v1.1/futopt/streaming
client.stock.url   // wss://fubon-api.fugle.tw/marketdata/v1.0/stock/streaming

new RestClient({ apiKey }).stock.baseUrl
// https://api.fugle.tw/marketdata/v1.0/stock

兩個都是唯讀、連線前就讀得到(取 .futopt 只建物件不連線),而且由 stock / futopt 子類別直接繼承——兩邊都只需要在基底類別加一個 getter。

設計取捨

放 client 不放 factory。 「連到哪」是 client 的性質,而 client 本來就是持有 socket 的東西。放 factory 會變成 client.urlFor('futopt'),但 product 在你拿到 client.futopt 的當下就確定了,再傳一次是多餘的。

WS 叫 url,REST 叫 baseUrl REST 那個真的是 base——endpoint 會往後接;WS 那個是完整位址,叫 base 會誤導。

只給 URL,不給 version 討論過是否要另外開 client.futopt.version === 'v1.1'。完整 URL 在 debug 時資訊更足(版本、host、product path 一次到位),而單獨的 version 需求目前還沒有人提。真的要加,也是後續三行的事。

測試

167 passed。既有的 URL 斷言全部改讀公開 accessor,@ts-ignore 從約 20 處降到 2 處——剩下那兩處是讀 private method 和 socket,跟這件事無關。

沒有另外加「accessor 專用」的測試:那些斷言會跟已經改寫過的既有測試一字不差地重複,而既有測試現在本來就是透過 accessor 驗證的——accessor 壞了它們會先紅。

相關

延續 #11baseUrl 與版本分離)。這個 PR 補的是那次改動留下的可見性缺口。

🤖 Generated with Claude Code

https://claude.ai/code/session_01VGBMNGKfgHPyNGMkHMcaJH

Since baseUrl became host-and-prefix only, the SDK — not the caller — decides
the version segment. That left no way to answer "which version am I actually
on": options is protected, so even our own tests reached for it through
@ts-ignore.

WebSocketClient gains `url` (the full endpoint, version segment included) and
RestClient gains `baseUrl` (the prefix requests are built on). Both are
read-only, available before connecting, and inherited by the stock and futopt
subclasses.

The existing URL assertions now read through these accessors instead of
@ts-ignore, which drops that escape hatch from ~20 places to the two that
genuinely poke at private internals.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VGBMNGKfgHPyNGMkHMcaJH
@kevinypfan
kevinypfan merged commit 7590476 into release/v1.5.0 Aug 4, 2026
4 checks passed
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.

1 participant