use std::fmt;
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Clone, Deserialize, PartialEq, Serialize)]
#[serde(transparent)]
pub struct OpenApiDocument(Value);
impl OpenApiDocument {
pub const fn as_value(&self) -> &Value {
&self.0
}
pub fn into_value(self) -> Value {
self.0
}
pub fn version(&self) -> Option<&str> {
self.0.get("openapi").and_then(Value::as_str)
}
pub fn http_operation_count(&self) -> usize {
const METHODS: &[&str] = &[
"get", "head", "post", "put", "patch", "delete", "options", "trace",
];
self.0
.get("paths")
.and_then(Value::as_object)
.into_iter()
.flat_map(|paths| paths.values())
.filter_map(Value::as_object)
.map(|item| {
METHODS
.iter()
.filter(|method| item.contains_key(**method))
.count()
})
.sum()
}
}
impl From<Value> for OpenApiDocument {
fn from(value: Value) -> Self {
Self(value)
}
}
impl fmt::Debug for OpenApiDocument {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("OpenApiDocument")
.field("version", &self.version())
.field("http_operation_count", &self.http_operation_count())
.finish_non_exhaustive()
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn openapi_document_counts_only_http_operations() {
let value = json!({
"openapi": "3.0.3",
"paths": {
"/one": {"get": {}, "post": {}, "parameters": []},
"/two": {"delete": {}, "websocket": {}}
}
});
let document = OpenApiDocument::from(value.clone());
assert_eq!(document.version(), Some("3.0.3"));
assert_eq!(document.http_operation_count(), 3);
assert!(format!("{document:?}").contains("http_operation_count: 3"));
assert_eq!(document.as_value(), &value);
assert_eq!(document.into_value(), value);
let empty = OpenApiDocument::from(json!({}));
assert_eq!(empty.version(), None);
assert_eq!(empty.http_operation_count(), 0);
}
}