diff --git a/crates/arc-api/src/demo/mod.rs b/crates/arc-api/src/demo/mod.rs index 4d9b2c0ef..4ed1eb638 100644 --- a/crates/arc-api/src/demo/mod.rs +++ b/crates/arc-api/src/demo/mod.rs @@ -11,7 +11,7 @@ use axum::Json; use crate::error::ApiError; use crate::jwt_auth::AuthenticatedService; -use crate::server::{AppState, PaginationParams}; +use crate::server::{AppState, ListResponse, PaginationParams}; fn paginated_response(items: Vec, pagination: &PaginationParams) -> Response { let limit = pagination.limit.clamp(1, 100) as usize; @@ -23,7 +23,7 @@ fn paginated_response(items: Vec, pagination: &Paginatio } fn list_response(items: T) -> Response { - (StatusCode::OK, Json(json!({ "data": items, "meta": { "has_more": false } }))).into_response() + (StatusCode::OK, Json(ListResponse::new(items))).into_response() } // ── Runs ─────────────────────────────────────────────────────────────── diff --git a/crates/arc-api/src/server.rs b/crates/arc-api/src/server.rs index 338c22ab1..61e409e56 100644 --- a/crates/arc-api/src/server.rs +++ b/crates/arc-api/src/server.rs @@ -12,7 +12,6 @@ use tokio::sync::broadcast; use tokio_stream::wrappers::BroadcastStream; use tokio_stream::StreamExt; -use serde_json::json; use tracing::{error, info}; use arc_agent::LocalSandbox; @@ -45,6 +44,22 @@ pub struct PaginationParams { pub offset: u32, } +/// Non-paginated list response wrapper with `has_more: false`. +#[derive(serde::Serialize)] +pub struct ListResponse { + data: T, + meta: PaginationMeta, +} + +impl ListResponse { + pub fn new(data: T) -> Self { + Self { + data, + meta: PaginationMeta { has_more: false }, + } + } +} + /// Snapshot of a managed run. struct ManagedRun { dot_source: String, @@ -645,7 +660,7 @@ async fn get_questions( Some(managed_run) => { let interviewer = match &managed_run.interviewer { Some(i) => i, - None => return (StatusCode::OK, Json(json!({ "data": Vec::::new(), "meta": { "has_more": false } }))).into_response(), + None => return (StatusCode::OK, Json(ListResponse::new(Vec::::new()))).into_response(), }; let pending = interviewer.pending_questions(); let questions: Vec = pending @@ -666,7 +681,7 @@ async fn get_questions( allow_freeform: pq.question.allow_freeform, }) .collect(); - (StatusCode::OK, Json(json!({ "data": questions, "meta": { "has_more": false } }))).into_response() + (StatusCode::OK, Json(ListResponse::new(questions))).into_response() } None => ApiError::not_found("Run not found.").into_response(), }