typed-openrpc 0.1.1

Typed JSON-RPC 2.0 method definitions with OpenRPC document generation.
Documentation
use serde_json::{json, Value};

use crate::{registry::Registry, rpc_method::MethodDoc};

/// Metadata describing the OpenRPC document.
#[derive(Clone, Debug)]
pub struct OpenRpcInfo {
    pub title: String,
    pub version: String,
    pub description: Option<String>,
}

impl Default for OpenRpcInfo {
    fn default() -> Self {
        Self {
            title: "Generated API".to_string(),
            version: "1.0.0".to_string(),
            description: None,
        }
    }
}

impl OpenRpcInfo {
    fn to_value(&self) -> Value {
        let mut info = json!({
            "title": self.title,
            "version": self.version,
        });

        if let Some(description) = &self.description {
            info["description"] = json!(description);
        }

        info
    }
}

impl Registry {
    /// Convert all registered methods into an OpenRPC JSON document.
    pub fn generate_openrpc_doc(&self) -> Value {
        generate_openrpc_doc_with_info(self, &OpenRpcInfo::default())
    }

    pub fn generate_openrpc_doc_with_info(&self, info: &OpenRpcInfo) -> Value {
        generate_openrpc_doc_with_info(self, info)
    }
}

/// Convert all registered methods into an OpenRPC JSON document, using custom metadata.
fn generate_openrpc_doc_with_info(registry: &Registry, info: &OpenRpcInfo) -> Value {
    let methods = registry
        .methods()
        .iter()
        .map(method_to_value)
        .collect::<Vec<_>>();

    json!({
        "openrpc": "1.2.6",
        "info": info.to_value(),
        "methods": methods,
    })
}

fn method_to_value(method: &MethodDoc) -> Value {
    json!({
        "name": method.name.clone(),
        "summary": method.summary.clone(),
        "deprecated": method.deprecation.clone(),
        "tags": method.tags.clone(),
        "params": [{
            "name": "params",
            "schema": method.params_schema.clone(),
            "required": true,
        }],
        "result": {
            "name": "result",
            "schema": method.result_schema.clone(),
        }
    })
}