Skip to content

Commit 928af7d

Browse files
committed
Improve adapters developer guide
1 parent 1202e63 commit 928af7d

File tree

1 file changed

+24
-8
lines changed

1 file changed

+24
-8
lines changed

docs/developer_guide/adapters.md

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@ crates/adapters/your_adapter/
2727
│ ├── common/ # Shared types and utilities
2828
│ ├── http/ # HTTP client implementation
2929
│ │ ├── client.rs # HTTP client with authentication
30+
│ │ ├── models.rs # Structs for REST payloads
31+
│ │ ├── query.rs # Request and query builders
3032
│ │ └── parse.rs # Response parsing functions
3133
│ ├── websocket/ # WebSocket implementation
3234
│ │ ├── client.rs # WebSocket client
35+
│ │ ├── messages.rs # Structs for stream payloads
3336
│ │ └── parse.rs # Message parsing functions
3437
│ ├── python/ # PyO3 Python bindings
3538
│ ├── config.rs # Configuration structures
@@ -119,17 +122,30 @@ crates/adapters/your_adapter/
119122

120123
---
121124

122-
## REST API field-mapping guideline
125+
## Common Rust adapter patterns
123126

124-
When translating a venue’s REST payload into our domain model **avoid renaming** the upstream
125-
fields unless there is a compelling reason (e.g. a clash with reserved keywords). The only
126-
transformation we apply by default is **camelCase → snake_case**.
127+
- **Common code (`common/`)**: Group venue constants, credential helpers, enums, and reusable parsers under `src/common`. Adapters such as OKX keep submodules like `consts`, `credential`, `enums`, and `urls` alongside a `testing` module for fixtures, providing a single place for cross-cutting pieces.
128+
- **Configurations (`config.rs`)**: Expose typed config structs in `src/config.rs` so Python callers toggle venue-specific behaviour (see how OKX wires demo URLs, retries, and channel flags). Keep defaults minimal and delegate URL selection to helpers in `common::urls`.
129+
- **Error taxonomy (`error.rs`)**: Centralise HTTP/WebSocket failure handling in an adapter-specific error enum. BitMEX, for example, separates retryable, non-retryable, and fatal variants while embedding the original transport error—follow that shape so operational tooling can react consistently.
130+
- **Python exports (`python/mod.rs`)**: Mirror the Rust surface area through PyO3 modules by re-exporting clients, enums, and helper functions. When new functionality lands in Rust, add it to `python/mod.rs` so the Python layer stays in sync (the OKX adapter is a good reference).
131+
- **String interning**: Use `ustr::Ustr` for any non-unique strings the platform stores repeatedly (venues, symbols, instrument IDs) to minimise allocations and comparisons.
132+
- **Testing helpers (`common/testing.rs`)**: Store shared fixtures and payload loaders in `src/common/testing.rs` for use across HTTP and WebSocket unit tests. This keeps `#[cfg(test)]` helpers out of production modules and encourages reuse.
127133

128-
Keeping the external names intact makes it trivial to debug payloads, compare captures against the
129-
Rust structs, and speeds up onboarding for new contributors who have the venue’s API reference
130-
open side-by-side.
134+
## Modeling venue payloads
131135

132-
---
136+
Use the following conventions when mirroring upstream schemas in Rust.
137+
138+
### REST models (`http::models` and `http::query`)
139+
140+
- Put request and response representations in `src/http/models.rs` and derive `serde::Deserialize` (add `serde::Serialize` when the adapter sends data back).
141+
- Mirror upstream payload names with blanket casing attributes such as `#[serde(rename_all = "camelCase")]` or `#[serde(rename_all = "snake_case")]`; only add per-field renames when the upstream key would be an invalid Rust identifier or collide with a keyword (for example `#[serde(rename = "type")] pub order_type: String`).
142+
- Keep helper structs for query parameters in `src/http/query.rs`, deriving `serde::Serialize` to remain type-safe and reusing constants from `common::consts` instead of duplicating literals.
143+
144+
### WebSocket messages (`websocket::messages`)
145+
146+
- Define streaming payload types in `src/websocket/messages.rs`, giving each venue topic a struct or enum that mirrors the upstream JSON.
147+
- Apply the same naming guidance as REST models: rely on blanket casing renames and keep field names aligned with the venue unless syntax forces a change; consider serde helpers such as `#[serde(tag = "op")]` or `#[serde(flatten)]` and document the choice.
148+
- Note any intentional deviations from the upstream schema in code comments and module docs so other contributors can follow the mapping quickly.
133149

134150
## Template for building a Python adapter
135151

0 commit comments

Comments
 (0)