use dropshot::endpoint;
use dropshot::ApiDescription;
use dropshot::ClientSpecifiesVersionInHeader;
use dropshot::ConfigDropshot;
use dropshot::ConfigLogging;
use dropshot::ConfigLoggingLevel;
use dropshot::HttpError;
use dropshot::HttpResponseOk;
use dropshot::RequestContext;
use dropshot::ServerBuilder;
use dropshot::VersionPolicy;
use http::HeaderName;
use schemars::JsonSchema;
use serde::Serialize;
#[tokio::main]
async fn main() -> Result<(), String> {
let config_dropshot = ConfigDropshot {
bind_address: "127.0.0.1:12345".parse().unwrap(),
..Default::default()
};
let config_logging =
ConfigLogging::StderrTerminal { level: ConfigLoggingLevel::Debug };
let log = config_logging
.to_logger("example-basic")
.map_err(|error| format!("failed to create logger: {}", error))?;
let mut api = ApiDescription::new();
api.register(v1::get_thing1).unwrap();
api.register(v2::get_thing1).unwrap();
api.register(get_thing2).unwrap();
let args: Vec<_> = std::env::args().skip(1).collect();
if args.is_empty() {
Err(String::from("expected subcommand: \"run\" or \"openapi\""))
} else if args[0] == "openapi" {
if args.len() != 2 {
return Err(String::from(
"subcommand \"openapi\": expected exactly one argument",
));
}
let version: semver::Version =
args[1].parse().map_err(|e| format!("expected semver: {}", e))?;
let _ = api
.openapi("Example API with versioning", version)
.write(&mut std::io::stdout());
Ok(())
} else if args[0] == "run" {
let api_context = ();
let header_name = "dropshot-demo-version"
.parse::<HeaderName>()
.map_err(|_| String::from("demo header name was not valid"))?;
let max_version = semver::Version::new(2, 0, 0);
let version_impl =
ClientSpecifiesVersionInHeader::new(header_name, max_version);
let version_policy = VersionPolicy::Dynamic(Box::new(version_impl));
let server = ServerBuilder::new(api, api_context, log)
.config(config_dropshot)
.version_policy(version_policy)
.start()
.map_err(|error| format!("failed to create server: {}", error))?;
server.await
} else {
Err(String::from("unknown subcommand"))
}
}
const TWO_DOT_OH: semver::Version = semver::Version::new(2, 0, 0);
mod v1 {
use super::*;
#[derive(Serialize, JsonSchema)]
struct Thing1 {
thing1_early: &'static str,
}
#[endpoint {
method = GET,
path = "/thing1",
versions = "1.0.0"..TWO_DOT_OH
}]
pub async fn get_thing1(
_rqctx: RequestContext<()>,
) -> Result<HttpResponseOk<Thing1>, HttpError> {
Ok(HttpResponseOk(Thing1 { thing1_early: "hello from an early v1" }))
}
}
mod v2 {
use super::*;
#[derive(Serialize, JsonSchema)]
struct Thing1 {
thing1_late: &'static str,
}
#[endpoint {
method = GET,
path = "/thing1",
versions = "2.0.0"..
}]
pub async fn get_thing1(
_rqctx: RequestContext<()>,
) -> Result<HttpResponseOk<Thing1>, HttpError> {
Ok(HttpResponseOk(Thing1 { thing1_late: "hello from a LATE v1" }))
}
}
#[derive(Serialize, JsonSchema)]
struct Thing2 {
thing2: &'static str,
}
#[endpoint {
method = GET,
path = "/thing2",
}]
pub async fn get_thing2(
_rqctx: RequestContext<()>,
) -> Result<HttpResponseOk<Thing2>, HttpError> {
Ok(HttpResponseOk(Thing2 { thing2: "hello from any version" }))
}