add_coco_server Data Payload Structure and Validation in the Coco App
The add_coco_server Tauri command accepts only a base URL string from the frontend, then constructs a complete Server data payload by querying the remote provider/_info endpoint and validates it through duplicate detection, HTTP health checks, and strict Serde deserialization before persisting the entry.
The add_coco_server function in the infinilabs/coco-app repository serves as the primary backend interface for registering new Coco search servers in the desktop application. Rather than receiving a complete data object from the frontend, the command orchestrates a sophisticated validation pipeline that fetches, transforms, and verifies server metadata before storage.
Input Parameters: Minimal Frontend Contract
The frontend invocation supplies only one argument: the server’s base URL (endpoint). The command signature in src-tauri/src/server/servers.rs accepts this single string and immediately begins the payload construction process.
// Frontend invocation (TypeScript)
import { invoke } from '@tauri-apps/api/tauri';
const server = await invoke<Server>('add_coco_server', {
endpoint: 'https://my.coco.server'
});
Data Payload Construction Pipeline
The backend constructs the full data payload through a sequence of network requests and transformations. This occurs in the add_coco_server implementation at lines 1000–1069 of src-tauri/src/server/servers.rs.
Endpoint Sanitization and Duplicate Detection
First, the command trims trailing slashes from the supplied URL and checks for existing entries via check_endpoint_exists. If the endpoint already exists in the local store, the command aborts immediately with an error response.
// servers.rs:1000-1008
let endpoint = trim_endpoint_last_forward_slash(&endpoint);
if check_endpoint_exists(&endpoint) {
return Err("Server already exists".to_string());
}
Fetching Provider Metadata
The command constructs the URL <endpoint>/provider/_info using provider_info_url(endpoint) and sends a GET request via HttpClient::send_raw_request. This fetches the server’s public metadata including provider details, version information, and authentication configuration.
HTTP Response Validation
If the remote server returns any status other than 200 OK, the command returns the error message "This Coco server is possibly down" and terminates. The response body is then read as text using get_response_body_text, with I/O errors converted to user-friendly messages via report_error.
JSON Deserialization into Server Struct
The response body is parsed using Serde (serde_json::from_str) into the Server struct. Deserialization failures propagate as "Failed to deserialize the response", enforcing strict schema compliance.
// servers.rs:1030-1032
let mut server: Server = serde_json::from_str(&body)
.map_err(|e| format!("Failed to deserialize the response: {}", e))?;
The Server Struct: Complete Payload Definition
The final data payload structure is defined in src-tauri/src/common/server.rs at lines 40–74. This struct represents the complete server configuration persisted to local storage.
| Field | Type | Description |
|---|---|---|
id |
String |
Unique identifier (auto-generated UUID if absent) |
builtin |
bool |
Flag for internal system servers |
name |
String |
Human-readable display name (defaults to Coco Server) |
endpoint |
String |
Base URL of the remote server |
provider |
Provider |
Metadata including name, icon, website, EULA, privacy policy |
version |
Version |
Server version string |
minimal_client_version |
Option<MinimalClientVersion> |
Minimum compatible client version |
updated |
String |
ISO timestamp of last provider-info fetch |
enabled |
bool |
UI visibility flag (default true) |
public |
bool |
Indicates if server requires authentication |
available |
bool |
Calculated availability status |
health |
Option<Health> |
Runtime health-check data |
profile |
Option<UserProfile> |
Authenticated user profile |
auth_provider |
AuthProvider |
SSO configuration URL |
priority |
u32 |
Display ordering hint |
stats |
Option<HashMap<String, Value>> |
Runtime statistics |
Validation Logic Implementation
The command performs four distinct validation layers to ensure data integrity before persistence.
Duplicate Endpoint Prevention
The check_endpoint_exists function queries the local server registry to prevent duplicate registrations. This occurs before any network requests, ensuring idempotent behavior.
Network Health Verification
The command strictly validates that the provider/_info endpoint returns HTTP 200. Any other status code—including redirects or authentication challenges—results in immediate failure with a descriptive error message.
Schema Validation via Serde
The deserialization step enforces type safety through Rust’s type system. Required fields must be present and correctly typed. Optional fields utilize #[serde(default = ...)] attributes to populate sensible defaults when missing from the remote response.
Logical Consistency and Normalization
Post-deserialization, the command applies business logic validation:
- ID Generation: If the remote response lacks an
id, the command generates a new UUID viaUuid::new - Name Fallback: Empty
namefields default to "Coco Server" - Availability Calculation:
- Public servers (
public: true) automatically setavailable: true - Private servers check the token cache via
get_server_token(&server.id)and assert that no token exists for new servers, forcingavailable: falseuntil authentication occurs
- Public servers (
// servers.rs:1046-1058
if server.public {
server.available = true;
} else {
assert!(get_server_token(&server.id).is_none(), "New private server should not have existing token");
server.available = false;
}
Code Implementation Examples
Frontend TypeScript Integration
import { invoke } from '@tauri-apps/api/tauri';
import type { Server } from '@/types';
async function registerCocoServer(endpoint: string): Promise<Server> {
try {
const server = await invoke<Server>('add_coco_server', { endpoint });
console.log('Server registered:', server.id, server.name);
return server;
} catch (err) {
console.error('Registration failed:', err);
throw err;
}
}
Backend Rust Command Signature
// src-tauri/src/lib.rs
#[tauri::command]
pub async fn add_coco_server(
app_handle: AppHandle,
endpoint: String
) -> Result<Server, String> {
// Implementation in src-tauri/src/server/servers.rs
}
Summary
- Single Input: The command requires only a base URL endpoint from the frontend, constructing the full payload server-side
- Network Dependency: Validation requires successful HTTP 200 response from the remote
provider/_infoendpoint - Strict Schema: The
Serverstruct incommon/server.rsdefines the complete payload shape with Serde enforcing type safety - Auto-Generation: Missing
idfields receive UUIDs and empty names default to "Coco Server" during normalization - Availability Logic: Public servers are immediately available; private servers require authentication before becoming available
- Persistence: Valid servers are saved via
save_serverandpersist_serversafter passing all validation checks
Frequently Asked Questions
What data does the frontend need to send to add_coco_server?
The frontend sends only a single string parameter: endpoint. This is the base URL of the Coco server (e.g., https://search.example.com). The backend handles all metadata retrieval and payload construction by querying the server’s provider/_info endpoint.
How does add_coco_server prevent duplicate server entries?
Before making network requests, the command calls check_endpoint_exists to verify the trimmed URL is not already registered. If a match is found, the function returns an error immediately without contacting the remote server.
What determines if a server is marked as available?
The available boolean is set based on the server’s public flag and token cache state. Public servers are automatically marked available (true). Private servers must not have an existing token in the cache and are forced to available: false until the user authenticates.
Where is the Server data structure defined?
The Server struct is defined in src-tauri/src/common/server.rs at lines 40–74. This file contains the complete payload schema including nested types like Provider, Version, Health, and AuthProvider that populate the final server object returned to the frontend.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →