Skip to main content

bevy_remote/schemas/
open_rpc.rs

1//! Module with trimmed down `OpenRPC` document structs.
2//! It tries to follow this standard: <https://spec.open-rpc.org>
3use bevy_platform::collections::HashMap;
4use bevy_utils::default;
5use serde::{Deserialize, Serialize};
6
7use crate::RemoteMethods;
8
9use super::json_schema::JsonSchemaBevyType;
10
11/// Represents an `OpenRPC` document as defined by the `OpenRPC` specification.
12#[derive(Debug, Serialize, Deserialize)]
13#[serde(rename_all = "camelCase")]
14pub struct OpenRpcDocument {
15    /// The version of the `OpenRPC` specification being used.
16    pub openrpc: String,
17    /// Informational metadata about the document.
18    pub info: InfoObject,
19    /// List of RPC methods defined in the document.
20    pub methods: Vec<MethodObject>,
21    /// Optional list of server objects that provide the API endpoint details.
22    pub servers: Option<Vec<ServerObject>>,
23}
24
25/// Contains metadata information about the `OpenRPC` document.
26#[derive(Serialize, Deserialize, Debug)]
27#[serde(rename_all = "camelCase")]
28pub struct InfoObject {
29    /// The title of the API or document.
30    pub title: String,
31    /// The version of the API.
32    pub version: String,
33    /// An optional description providing additional details about the API.
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub description: Option<String>,
36    /// A collection of custom extension fields.
37    #[serde(flatten)]
38    pub extensions: HashMap<String, serde_json::Value>,
39}
40
41impl Default for InfoObject {
42    fn default() -> Self {
43        Self {
44            title: "Bevy Remote Protocol".to_owned(),
45            version: env!("CARGO_PKG_VERSION").to_owned(),
46            description: None,
47            extensions: Default::default(),
48        }
49    }
50}
51
52/// Describes a server hosting the API as specified in the `OpenRPC` document.
53#[derive(Serialize, Deserialize, Debug, Default)]
54#[serde(rename_all = "camelCase")]
55pub struct ServerObject {
56    /// The name of the server.
57    pub name: String,
58    /// The URL endpoint of the server.
59    pub url: String,
60    /// An optional description of the server.
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub description: Option<String>,
63    /// Additional custom extension fields.
64    #[serde(flatten)]
65    pub extensions: HashMap<String, serde_json::Value>,
66}
67
68/// Represents an RPC method in the `OpenRPC` document.
69#[derive(Serialize, Deserialize, Debug, Default)]
70#[serde(rename_all = "camelCase")]
71pub struct MethodObject {
72    #[expect(
73        clippy::doc_markdown,
74        reason = "In this case, we are referring to a string, so using quotes instead of backticks makes sense."
75    )]
76    /// The method name (e.g., "world.get_components")
77    pub name: String,
78    /// An optional short summary of the method.
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub summary: Option<String>,
81    /// An optional detailed description of the method.
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub description: Option<String>,
84    /// Parameters for the RPC method
85    #[serde(default)]
86    pub params: Vec<Parameter>,
87    // /// The expected result of the method
88    // #[serde(skip_serializing_if = "Option::is_none")]
89    // pub result: Option<Parameter>,
90    /// Additional custom extension fields.
91    #[serde(flatten)]
92    pub extensions: HashMap<String, serde_json::Value>,
93}
94
95/// Represents an RPC method parameter in the `OpenRPC` document.
96#[derive(Serialize, Deserialize, Debug)]
97#[serde(rename_all = "camelCase")]
98pub struct Parameter {
99    /// Parameter name
100    pub name: String,
101    /// Parameter description
102    #[serde(skip_serializing_if = "Option::is_none")]
103    pub description: Option<String>,
104    /// JSON schema describing the parameter
105    pub schema: JsonSchemaBevyType,
106    /// Additional custom extension fields.
107    #[serde(flatten)]
108    pub extensions: HashMap<String, serde_json::Value>,
109}
110
111impl From<&RemoteMethods> for Vec<MethodObject> {
112    fn from(value: &RemoteMethods) -> Self {
113        value
114            .methods()
115            .iter()
116            .map(|e| MethodObject {
117                name: e.to_owned(),
118                ..default()
119            })
120            .collect()
121    }
122}