testing a Router::api_dump method

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2019-06-12 17:11:44 +02:00
parent 536072c712
commit a64832aac2
3 changed files with 98 additions and 2 deletions

View File

@ -46,6 +46,12 @@ fn main() {
let www_dir = args.next().expect("expected a www/ subdirectory"); let www_dir = args.next().expect("expected a www/ subdirectory");
api::set_www_dir(www_dir.to_string()); api::set_www_dir(www_dir.to_string());
// show our api info:
println!(
"{}",
serde_json::to_string_pretty(&api::ROUTER.api_dump()).unwrap()
);
// Construct our SocketAddr to listen on... // Construct our SocketAddr to listen on...
let addr = ([0, 0, 0, 0], 3000).into(); let addr = ([0, 0, 0, 0], 3000).into();

View File

@ -5,7 +5,7 @@ use std::sync::Once;
use failure::Error; use failure::Error;
use http::Response; use http::Response;
use serde_json::Value; use serde_json::{json, Value};
/// Method entries in a `Router` are actually just `&dyn ApiMethodInfo` trait objects. /// Method entries in a `Router` are actually just `&dyn ApiMethodInfo` trait objects.
/// This contains all the info required to call, document, or command-line-complete parameters for /// This contains all the info required to call, document, or command-line-complete parameters for
@ -31,6 +31,18 @@ pub struct Parameter {
pub type_info: fn() -> &'static TypeInfo, pub type_info: fn() -> &'static TypeInfo,
} }
impl Parameter {
pub fn api_dump(&self) -> (&'static str, Value) {
(
self.name,
json!({
"description": self.description,
"type": (self.type_info)().name,
}),
)
}
}
/// Bare type info. Types themselves should also have a description, even if a method's parameter /// Bare type info. Types themselves should also have a description, even if a method's parameter
/// usually overrides it. Ideally we can hyperlink the parameter to the type information in the /// usually overrides it. Ideally we can hyperlink the parameter to the type information in the
/// generated documentation. /// generated documentation.
@ -40,6 +52,12 @@ pub struct TypeInfo {
pub complete_fn: Option<CompleteFn>, pub complete_fn: Option<CompleteFn>,
} }
impl TypeInfo {
pub fn api_dump(&self) -> Value {
Value::String(self.name.to_string())
}
}
/// Until we can slap `#[api]` onto all the functions we can start translating our existing /// Until we can slap `#[api]` onto all the functions we can start translating our existing
/// `ApiMethod` structs to this new layout. /// `ApiMethod` structs to this new layout.
/// Otherwise this is mostly there so we can run the tests in the tests subdirectory without /// Otherwise this is mostly there so we can run the tests in the tests subdirectory without
@ -80,6 +98,25 @@ impl<Body> ApiMethodInfo<Body> for ApiMethod<Body> {
} }
} }
impl<Body> dyn ApiMethodInfo<Body> + Send + Sync {
pub fn api_dump(&self) -> Value {
let parameters = Value::Object(std::iter::FromIterator::from_iter(
self.parameters()
.iter()
.map(|p| p.api_dump())
.map(|(name, value)| (name.to_string(), value)),
));
json!({
"description": self.description(),
"protected": self.protected(),
"reload-timezone": self.reload_timezone(),
"parameters": parameters,
//"returns": self.return_type().api_dump()?, <- add api_dump() to TypeInfo
})
}
}
/// We're supposed to only use types in the API which implement `ApiType`, which forces types ot /// We're supposed to only use types in the API which implement `ApiType`, which forces types ot
/// have a `verify` method. The idea is that all parameters used in the API are documented /// have a `verify` method. The idea is that all parameters used in the API are documented
/// somewhere with their formats and limits, which are checked when entering and leaving API entry /// somewhere with their formats and limits, which are checked when entering and leaving API entry

View File

@ -2,7 +2,8 @@
use std::collections::HashMap; use std::collections::HashMap;
use serde_json::Value; use failure::Error;
use serde_json::{json, Value};
use super::ApiMethodInfo; use super::ApiMethodInfo;
@ -110,6 +111,58 @@ where
Some((this, matched_params.map(Value::Object))) Some((this, matched_params.map(Value::Object)))
} }
pub fn api_dump(&self) -> Value {
let mut this = serde_json::Map::<String, Value>::new();
if let Some(get) = self.get {
this.insert("GET".to_string(), get.api_dump());
}
if let Some(put) = self.put {
this.insert("PUT".to_string(), put.api_dump());
}
if let Some(post) = self.post {
this.insert("POST".to_string(), post.api_dump());
}
if let Some(delete) = self.delete {
this.insert("DELETE".to_string(), delete.api_dump());
}
match &self.subroute {
None => (),
Some(SubRoute::Wildcard(name)) => {
this.insert("wildcard".to_string(), Value::String(name.to_string()));
}
Some(SubRoute::Directories(subdirs)) => {
for (dir, router) in subdirs.iter() {
this.insert(dir.to_string(), router.api_dump());
}
}
Some(SubRoute::Parameter(name, other)) => {
this.insert(
"sub-router".to_string(),
json!({
"parameter": name,
"router": other.api_dump(),
}),
);
}
}
Value::Object(this)
}
}
//
// Router as a builder methods:
//
impl<Body> Router<Body>
where
Self: Default,
{
/// Builder method to provide a `GET` method info. /// Builder method to provide a `GET` method info.
pub fn get<I>(mut self, method: &'static I) -> Self pub fn get<I>(mut self, method: &'static I) -> Self
where where