use dropshot::endpoint;
use dropshot::ApiDescription;
use dropshot::ConfigDropshot;
use dropshot::ConfigLogging;
use dropshot::ConfigLoggingLevel;
use dropshot::EmptyScanParams;
use dropshot::HttpError;
use dropshot::HttpResponseOk;
use dropshot::PaginationParams;
use dropshot::Query;
use dropshot::RequestContext;
use dropshot::ResultsPage;
use dropshot::ServerBuilder;
use dropshot::WhichPage;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use std::collections::BTreeMap;
use std::net::Ipv4Addr;
use std::net::SocketAddr;
use std::ops::Bound;
#[derive(Clone, JsonSchema, Serialize)]
struct Project {
name: String,
}
#[derive(Deserialize, JsonSchema, Serialize)]
struct ProjectPage {
name: String,
}
#[endpoint {
method = GET,
path = "/projects"
}]
async fn example_list_projects(
rqctx: RequestContext<BTreeMap<String, Project>>,
query: Query<PaginationParams<EmptyScanParams, ProjectPage>>,
) -> Result<HttpResponseOk<ResultsPage<Project>>, HttpError> {
let pag_params = query.into_inner();
let limit = rqctx.page_limit(&pag_params)?.get() as usize;
let tree = rqctx.context();
let projects = match &pag_params.page {
WhichPage::First(..) => {
tree.iter()
.take(limit)
.map(|(_, project)| project.clone())
.collect()
}
WhichPage::Next(ProjectPage { name: last_seen }) => {
tree.range((Bound::Excluded(last_seen.clone()), Bound::Unbounded))
.take(limit)
.map(|(_, project)| project.clone())
.collect()
}
};
Ok(HttpResponseOk(ResultsPage::new(
projects,
&EmptyScanParams {},
|p: &Project, _| ProjectPage { name: p.name.clone() },
)?))
}
#[tokio::main]
async fn main() -> Result<(), String> {
let port = std::env::args()
.nth(1)
.map(|p| p.parse::<u16>())
.transpose()
.map_err(|e| format!("failed to parse \"port\" argument: {}", e))?
.unwrap_or(0);
let mut tree = BTreeMap::new();
for n in 1..1000 {
let name = format!("project{:03}", n);
let project = Project { name: name.clone() };
tree.insert(name, project);
}
let ctx = tree;
let config_dropshot = ConfigDropshot {
bind_address: SocketAddr::from((Ipv4Addr::LOCALHOST, port)),
..Default::default()
};
let config_logging =
ConfigLogging::StderrTerminal { level: ConfigLoggingLevel::Debug };
let log = config_logging
.to_logger("example-pagination-basic")
.map_err(|error| format!("failed to create logger: {}", error))?;
let mut api = ApiDescription::new();
api.register(example_list_projects).unwrap();
let server = ServerBuilder::new(api, ctx, log)
.config(config_dropshot)
.start()
.map_err(|error| format!("failed to create server: {}", error))?;
server.await
}