1use crate::traits::MethodInfo;
4use std::collections::HashMap;
5
6pub fn render_docs(method_info: &HashMap<String, MethodInfo>) -> serde_json::Value {
8 let mut methods = serde_json::Map::new();
9
10 for (method_name, info) in method_info {
11 let mut method_doc = serde_json::Map::new();
12
13 method_doc.insert(
15 "summary".to_string(),
16 serde_json::Value::String(
17 info.description
18 .clone()
19 .unwrap_or_else(|| format!("Execute {} method", method_name)),
20 ),
21 );
22
23 let mut request_body = serde_json::Map::new();
25 let mut content = serde_json::Map::new();
26 let mut json_content = serde_json::Map::new();
27 let mut schema = serde_json::Map::new();
28
29 schema.insert(
30 "type".to_string(),
31 serde_json::Value::String("object".to_string()),
32 );
33
34 let mut properties = serde_json::Map::new();
35 properties.insert(
36 "jsonrpc".to_string(),
37 serde_json::json!({
38 "type": "string",
39 "enum": ["2.0"],
40 "description": "JSON-RPC version"
41 }),
42 );
43 properties.insert(
44 "method".to_string(),
45 serde_json::json!({
46 "type": "string",
47 "enum": [method_name],
48 "description": "Method name"
49 }),
50 );
51 properties.insert(
52 "id".to_string(),
53 serde_json::json!({
54 "oneOf": [
55 {"type": "string"},
56 {"type": "number"},
57 {"type": "null"}
58 ],
59 "description": "Request identifier"
60 }),
61 );
62
63 if let Some(params_schema) = &info.params_schema {
64 properties.insert("params".to_string(), params_schema.clone());
65 }
66
67 schema.insert(
68 "properties".to_string(),
69 serde_json::Value::Object(properties),
70 );
71 schema.insert(
72 "required".to_string(),
73 serde_json::json!(["jsonrpc", "method"]),
74 );
75
76 json_content.insert("schema".to_string(), serde_json::Value::Object(schema));
77 content.insert(
78 "application/json".to_string(),
79 serde_json::Value::Object(json_content),
80 );
81 request_body.insert("content".to_string(), serde_json::Value::Object(content));
82 request_body.insert("required".to_string(), serde_json::Value::Bool(true));
83
84 method_doc.insert(
85 "requestBody".to_string(),
86 serde_json::Value::Object(request_body),
87 );
88
89 let mut responses = serde_json::Map::new();
91 let mut success_response = serde_json::Map::new();
92 success_response.insert(
93 "description".to_string(),
94 serde_json::Value::String("Successful response".to_string()),
95 );
96
97 let mut success_content = serde_json::Map::new();
98 let mut success_json = serde_json::Map::new();
99 let mut success_schema = serde_json::Map::new();
100
101 success_schema.insert(
102 "type".to_string(),
103 serde_json::Value::String("object".to_string()),
104 );
105
106 let mut success_properties = serde_json::Map::new();
107 success_properties.insert(
108 "jsonrpc".to_string(),
109 serde_json::json!({
110 "type": "string",
111 "enum": ["2.0"]
112 }),
113 );
114 success_properties.insert(
115 "id".to_string(),
116 serde_json::json!({
117 "oneOf": [
118 {"type": "string"},
119 {"type": "number"},
120 {"type": "null"}
121 ]
122 }),
123 );
124
125 if let Some(result_schema) = &info.result_schema {
126 success_properties.insert("result".to_string(), result_schema.clone());
127 } else {
128 success_properties.insert(
129 "result".to_string(),
130 serde_json::json!({
131 "description": "Method result"
132 }),
133 );
134 }
135
136 success_schema.insert(
137 "properties".to_string(),
138 serde_json::Value::Object(success_properties),
139 );
140 success_schema.insert(
141 "required".to_string(),
142 serde_json::json!(["jsonrpc", "result"]),
143 );
144
145 success_json.insert(
146 "schema".to_string(),
147 serde_json::Value::Object(success_schema),
148 );
149 success_content.insert(
150 "application/json".to_string(),
151 serde_json::Value::Object(success_json),
152 );
153 success_response.insert(
154 "content".to_string(),
155 serde_json::Value::Object(success_content),
156 );
157
158 responses.insert(
159 "200".to_string(),
160 serde_json::Value::Object(success_response),
161 );
162
163 let error_response = serde_json::json!({
165 "description": "Error response",
166 "content": {
167 "application/json": {
168 "schema": {
169 "type": "object",
170 "properties": {
171 "jsonrpc": {
172 "type": "string",
173 "enum": ["2.0"]
174 },
175 "error": {
176 "type": "object",
177 "properties": {
178 "code": {
179 "type": "integer",
180 "description": "Error code"
181 },
182 "message": {
183 "type": "string",
184 "description": "Error message"
185 },
186 "data": {
187 "description": "Additional error data"
188 }
189 },
190 "required": ["code", "message"]
191 },
192 "id": {
193 "oneOf": [
194 {"type": "string"},
195 {"type": "number"},
196 {"type": "null"}
197 ]
198 }
199 },
200 "required": ["jsonrpc", "error"]
201 }
202 }
203 }
204 });
205
206 responses.insert("400".to_string(), error_response);
207 method_doc.insert(
208 "responses".to_string(),
209 serde_json::Value::Object(responses),
210 );
211
212 methods.insert(method_name.clone(), serde_json::Value::Object(method_doc));
213 }
214
215 serde_json::json!({
217 "openapi": "3.0.3",
218 "info": {
219 "title": "JSON-RPC API",
220 "description": "Auto-generated documentation for JSON-RPC methods",
221 "version": "1.0.0"
222 },
223 "servers": [
224 {
225 "url": "/",
226 "description": "JSON-RPC endpoint"
227 }
228 ],
229 "paths": {
230 "/": {
231 "post": {
232 "summary": "JSON-RPC endpoint",
233 "description": "Execute JSON-RPC methods",
234 "requestBody": {
235 "required": true,
236 "content": {
237 "application/json": {
238 "schema": {
239 "oneOf": methods.values().map(|method| {
240 if let serde_json::Value::Object(method_obj) = method {
241 if let Some(serde_json::Value::Object(request_body)) = method_obj.get("requestBody") {
242 if let Some(serde_json::Value::Object(content)) = request_body.get("content") {
243 if let Some(serde_json::Value::Object(json_content)) = content.get("application/json") {
244 return json_content.get("schema").cloned().unwrap_or(serde_json::Value::Null);
245 }
246 }
247 }
248 }
249 serde_json::Value::Null
250 }).collect::<Vec<_>>()
251 }
252 }
253 }
254 },
255 "responses": {
256 "200": {
257 "description": "Successful response",
258 "content": {
259 "application/json": {
260 "schema": {
261 "oneOf": [
262 {
263 "type": "object",
264 "properties": {
265 "jsonrpc": {"type": "string", "enum": ["2.0"]},
266 "result": {"description": "Method result"},
267 "id": {"oneOf": [{"type": "string"}, {"type": "number"}, {"type": "null"}]}
268 },
269 "required": ["jsonrpc", "result"]
270 },
271 {
272 "type": "object",
273 "properties": {
274 "jsonrpc": {"type": "string", "enum": ["2.0"]},
275 "error": {
276 "type": "object",
277 "properties": {
278 "code": {"type": "integer"},
279 "message": {"type": "string"},
280 "data": {"description": "Additional error data"}
281 },
282 "required": ["code", "message"]
283 },
284 "id": {"oneOf": [{"type": "string"}, {"type": "number"}, {"type": "null"}]}
285 },
286 "required": ["jsonrpc", "error"]
287 }
288 ]
289 }
290 }
291 }
292 }
293 }
294 }
295 }
296 },
297 "components": {
298 "schemas": {
299 "JsonRpcRequest": {
300 "type": "object",
301 "properties": {
302 "jsonrpc": {"type": "string", "enum": ["2.0"]},
303 "method": {"type": "string"},
304 "params": {"description": "Method parameters"},
305 "id": {"oneOf": [{"type": "string"}, {"type": "number"}, {"type": "null"}]}
306 },
307 "required": ["jsonrpc", "method"]
308 },
309 "JsonRpcSuccessResponse": {
310 "type": "object",
311 "properties": {
312 "jsonrpc": {"type": "string", "enum": ["2.0"]},
313 "result": {"description": "Method result"},
314 "id": {"oneOf": [{"type": "string"}, {"type": "number"}, {"type": "null"}]}
315 },
316 "required": ["jsonrpc", "result"]
317 },
318 "JsonRpcErrorResponse": {
319 "type": "object",
320 "properties": {
321 "jsonrpc": {"type": "string", "enum": ["2.0"]},
322 "error": {
323 "type": "object",
324 "properties": {
325 "code": {"type": "integer"},
326 "message": {"type": "string"},
327 "data": {"description": "Additional error data"}
328 },
329 "required": ["code", "message"]
330 },
331 "id": {"oneOf": [{"type": "string"}, {"type": "number"}, {"type": "null"}]}
332 },
333 "required": ["jsonrpc", "error"]
334 }
335 }
336 },
337 "tags": [
338 {
339 "name": "JSON-RPC",
340 "description": "JSON-RPC 2.0 methods"
341 }
342 ]
343 })
344}