-
-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Problem
Currently, Telegram Mini Apps require using two separate crates for frontend and backend:
- telegram-webapp-sdk - WASM frontend SDK with
TelegramInitData,TelegramUser, etc. - init-data-rs - Backend validation with
InitData,User, etc.
These crates have duplicate type definitions for the same Telegram data structures, leading to:
- Code duplication across crates
- Potential inconsistencies in field naming or types
- Manual conversion between frontend and backend types
- Increased maintenance burden when Telegram updates the API
Use Case
Full-stack Telegram Mini App development:
Frontend (WASM):
use telegram_webapp_sdk::TelegramInitData;
// Parse on client
let init_data = /* from SDK */;
send_to_backend(init_data);Backend:
use init_data_rs::InitData;
// Re-parse and validate on server
let init_data = init_data_rs::parse(raw_string)?;
init_data_rs::validate(raw_string, bot_token)?;The types are semantically identical but structurally separate.
Proposed Solution
Create a shared-types crate containing platform-agnostic Telegram type definitions:
[package]
name = "telegram-miniapp-types"
version = "0.1.0"
[dependencies]
serde = { version = "1", features = ["derive"] }
[features]
default = []
wasm = ["wasm-bindgen"] # Optional WASM serializationShared types:
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "wasm", derive(wasm_bindgen::JsValue))]
pub struct InitData {
pub auth_date: u64,
pub hash: String,
pub user: Option<User>,
pub receiver: Option<User>,
pub chat: Option<Chat>,
pub chat_type: Option<ChatType>,
pub chat_instance: Option<String>,
pub query_id: Option<String>,
pub start_param: Option<String>,
pub can_send_after: Option<u32>,
pub signature: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct User {
pub id: u64,
pub is_bot: Option<bool>,
pub first_name: String,
pub last_name: Option<String>,
pub username: Option<String>,
pub language_code: Option<String>,
pub is_premium: Option<bool>,
pub added_to_attachment_menu: Option<bool>,
pub allows_write_to_pm: Option<bool>,
pub photo_url: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Chat {
pub id: i64,
pub r#type: ChatType,
pub title: String,
pub username: Option<String>,
pub photo_url: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ChatType {
#[serde(rename = "sender")]
Sender,
#[serde(rename = "private")]
Private,
#[serde(rename = "group")]
Group,
#[serde(rename = "supergroup")]
Supergroup,
#[serde(rename = "channel")]
Channel,
}telegram-webapp-sdk integration:
[dependencies]
telegram-miniapp-types = "0.1"pub use telegram_miniapp_types::{InitData, User, Chat, ChatType};
// SDK-specific extensions
impl InitData {
pub fn from_telegram_context() -> Result<Self, JsValue> {
// Existing parsing logic
}
}init-data-rs integration:
[dependencies]
telegram-miniapp-types = "0.1"pub use telegram_miniapp_types::{InitData, User, Chat, ChatType};
pub fn parse(init_data: &str) -> Result<InitData, ParseError> {
// Existing parsing logic
}
pub fn validate(init_data: &str, bot_token: &str) -> Result<InitData, ValidationError> {
// Existing validation logic
}Benefits
- Single source of truth for Telegram type definitions
- Consistent API across frontend and backend
- Reduced maintenance - update once, works everywhere
- Better tooling - shared types enable better IDE support and type checking
- Easier testing - mock data works identically on both sides
- Future-proof - Telegram API updates require changes in one place
Migration Path
- Create
telegram-miniapp-typescrate with core types - Both
telegram-webapp-sdkandinit-data-rsdepend on it - Re-export types from shared crate
- Mark old type definitions as deprecated with migration guide
- Remove deprecated types in next major version
Alternative: Feature Flag Approach
If creating a separate crate is too complex initially, add validation to SDK as optional feature:
[features]
server-validation = ["hmac-sha256", "ed25519-dalek"]However, this pollutes the WASM bundle with unnecessary crypto code, so shared crate is preferred.
Ecosystem Impact
This pattern benefits the entire Telegram Mini Apps Rust ecosystem by establishing standard types that other crates can depend on.
Related Work
Similar pattern exists in other ecosystems:
jsonwebtokencrate for JWT types shared across auth librarieshttpcrate providing types for both client and server HTTP libraries