use std::collections::BTreeMap;
use endpoint_libs::model::{EndpointSchema, SchemaComponents, TypeRegistry};
use eyre::{Result, WrapErr};
use serde_json::{Value, json};
use crate::definitions::GenService;
use crate::docs::Data;
pub const ERROR_ENVELOPE: &str = "ErrorEnvelope";
pub fn build_registry(data: &Data) -> TypeRegistry {
let mut registry = TypeRegistry::new();
registry.add_all(crate::rust::shared_type_definitions(data).iter());
for service in &data.services {
for endpoint in &service.endpoints {
registry.add_endpoint(&endpoint.schema);
}
}
registry
}
pub fn visible_services(data: &Data, public_only: bool) -> Vec<GenService> {
data.services
.iter()
.filter_map(|service| {
let endpoints: Vec<_> = service
.endpoints
.iter()
.filter(|e| !public_only || e.frontend_facing)
.cloned()
.collect();
if endpoints.is_empty() {
return None;
}
let mut service = service.clone();
service.endpoints = endpoints;
Some(service)
})
.collect()
}
pub fn all_endpoints(services: &[GenService]) -> Vec<EndpointSchema> {
services
.iter()
.flat_map(|s| s.endpoints.iter().map(|e| e.schema.clone()))
.collect()
}
pub fn collect_components(services: &[GenService], registry: &TypeRegistry) -> Result<SchemaComponents> {
let endpoints = all_endpoints(services);
SchemaComponents::collect(&endpoints, registry).wrap_err("collecting shared schema components")
}
pub fn document_schemas(components: &SchemaComponents) -> BTreeMap<String, Value> {
let mut schemas = components.schemas.clone();
schemas.insert(ERROR_ENVELOPE.into(), error_envelope_schema());
schemas
}
pub fn error_envelope_schema() -> Value {
json!({
"type": "object",
"title": ERROR_ENVELOPE,
"description": "Standard error payload returned in place of a success response.",
"properties": {
"code": { "type": "integer", "description": "Error code from the global catalog." },
"message": { "type": "string" },
"params": { "type": "object", "description": "Error-specific fields, if any." },
},
"required": ["code", "message"],
})
}
pub fn error_code_list(schema: &EndpointSchema, error_codes: &[crate::definitions::ErrorCodeSchema]) -> Option<Value> {
if schema.errors.is_empty() {
return None;
}
let catalog: BTreeMap<&str, &crate::definitions::ErrorCodeSchema> =
error_codes.iter().map(|c| (c.name.as_str(), c)).collect();
let listed: Vec<Value> = schema
.errors
.iter()
.map(|error| {
let variant = error.code.variant();
let mut entry = serde_json::Map::new();
entry.insert("name".into(), json!(error.name));
entry.insert("code".into(), json!(variant));
if let Some(known) = catalog.get(variant) {
entry.insert("value".into(), json!(known.code));
if !known.description.is_empty() {
entry.insert("description".into(), json!(known.description));
}
}
if !error.message.is_empty() {
entry.insert("message".into(), json!(error.message));
}
Value::Object(entry)
})
.collect();
Some(Value::Array(listed))
}
pub fn document_title(data: &Data) -> String {
data.project_name.clone()
}