Architecture Overview
This section documents the architectural decisions and design patterns used in the Datto RMM API clients.
Design Principles
Section titled “Design Principles”- Auto-generation First - Types and client code are generated from OpenAPI specs
- Type Safety - Full type coverage with strict TypeScript and Rust
- Platform Agnostic - Support all 6 Datto RMM regional platforms
- OAuth Handled - Automatic token management and refresh
Code Generation Pipeline
Section titled “Code Generation Pipeline”OpenAPI Spec (specs/datto-rmm-openapi.json) │ ├──→ openapi-typescript ──→ TypeScript types │ └──→ progenitor ──→ Rust types (when 3.1.0 supported)TypeScript Generation
Section titled “TypeScript Generation”Uses openapi-typescript to generate types, paired with openapi-fetch for runtime:
- Input: OpenAPI 3.1.0 JSON specification
- Output: TypeScript type definitions in
src/generated/types.ts - Runtime:
openapi-fetchprovides a typed fetch wrapper
Rust Generation
Section titled “Rust Generation”Uses progenitor from Oxide Computer:
- Input: OpenAPI specification
- Output: Rust types and client code (when OpenAPI 3.1.0 is supported)
- Current Status: Manual client with OAuth, awaiting progenitor 3.1.0 support
Authentication Architecture
Section titled “Authentication Architecture”OAuth 2.0 Flow
Section titled “OAuth 2.0 Flow”┌─────────────┐ ┌─────────────┐ ┌─────────────┐│ Client │────→│ Token │────→│ Datto API ││ Request │ │ Manager │ │ Server │└─────────────┘ └─────────────┘ └─────────────┘ │ ├── Cache token in memory ├── Refresh 5 min before expiry └── Dedupe concurrent refreshesToken Management
Section titled “Token Management”Both clients implement:
- Token Caching - Store access tokens in memory
- Proactive Refresh - Refresh tokens before they expire (5 minute buffer)
- Request Deduplication - Prevent multiple concurrent refresh requests
- Middleware Pattern - Inject auth headers transparently
Platform Configuration
Section titled “Platform Configuration”All 6 Datto RMM platforms share the same API schema:
| Platform | Region | Base URL |
|---|---|---|
| Pinotage | - | https://pinotage-api.centrastage.net/api |
| Merlot | - | https://merlot-api.centrastage.net/api |
| Concord | - | https://concord-api.centrastage.net/api |
| Vidal | - | https://vidal-api.centrastage.net/api |
| Zinfandel | - | https://zinfandel-api.centrastage.net/api |
| Syrah | - | https://syrah-api.centrastage.net/api |
The platform is selected at client creation time and determines:
- API base URL
- OAuth token endpoint
Package Architecture
Section titled “Package Architecture”TypeScript (datto-rmm-api)
Section titled “TypeScript (datto-rmm-api)”┌─────────────────────────────────────────────────┐│ index.ts ││ (main exports & re-exports) │└─────────────────────────────────────────────────┘ │ │ │ ▼ ▼ ▼┌─────────────┐ ┌─────────────┐ ┌─────────────┐│ client.ts │ │ platforms.ts│ │ auth/ ││ (factory) │ │ (URLs/enum) │ │ (OAuth) │└─────────────┘ └─────────────┘ └─────────────┘ │ │ ▼ ▼┌─────────────────────────────┐ ┌─────────────┐│ generated/types.ts │ │ middleware ││ (auto-generated types) │ │ (inject) │└─────────────────────────────┘ └─────────────┘Rust (datto-api)
Section titled “Rust (datto-api)”┌─────────────────────────────────────────────────┐│ lib.rs ││ (main exports) │└─────────────────────────────────────────────────┘ │ │ ▼ ▼┌─────────────┐ ┌─────────────┐│ client.rs │ │platforms.rs ││ (DattoClient)│ │ (Platform) │└─────────────┘ └─────────────┘ │ ▼┌─────────────────────────────┐│ generated.rs ││ (progenitor output) │└─────────────────────────────┘Error Handling
Section titled “Error Handling”TypeScript
Section titled “TypeScript”Uses the openapi-fetch error model:
const { data, error, response } = await client.GET('/path');// data: typed response body (if success)// error: typed error body (if error)// response: raw Response objectUses a typed Error enum:
pub enum Error { HttpClient(reqwest::Error), Auth(String), Api { status: u16, message: String },}