open_rpc_schema/
document.rs

1use schemars::gen::SchemaSettings;
2use schemars::schema::RootSchema;
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7extern crate serde_json;
8
9#[derive(Serialize, Deserialize, Clone)]
10pub enum Openrpc {
11    #[serde(rename = "1.2.6")]
12    V26,
13    #[serde(rename = "1.2.5")]
14    V25,
15    #[serde(rename = "1.2.4")]
16    V24,
17    #[serde(rename = "1.2.3")]
18    V23,
19    #[serde(rename = "1.2.2")]
20    V22,
21    #[serde(rename = "1.2.1")]
22    V21,
23    #[serde(rename = "1.2.0")]
24    V20,
25    #[serde(rename = "1.1.12")]
26    V112,
27    #[serde(rename = "1.1.11")]
28    V111,
29    #[serde(rename = "1.1.10")]
30    V110,
31    #[serde(rename = "1.1.9")]
32    V19,
33    #[serde(rename = "1.1.8")]
34    V18,
35    #[serde(rename = "1.1.7")]
36    V17,
37    #[serde(rename = "1.1.6")]
38    V16,
39    #[serde(rename = "1.1.5")]
40    V15,
41    #[serde(rename = "1.1.4")]
42    V14,
43    #[serde(rename = "1.1.3")]
44    V13,
45    #[serde(rename = "1.1.2")]
46    V12,
47    #[serde(rename = "1.1.1")]
48    V11,
49    #[serde(rename = "1.1.0")]
50    V10,
51    #[serde(rename = "1.0.0")]
52    V00,
53    #[serde(rename = "1.0.0-rc1")]
54    V00Rc1,
55    #[serde(rename = "1.0.0-rc0")]
56    V00Rc0,
57}
58
59pub type InfoObjectProperties = String;
60pub type InfoObjectDescription = String;
61pub type InfoObjectTermsOfService = String;
62pub type InfoObjectVersion = String;
63pub type ContactObjectName = String;
64pub type ContactObjectEmail = String;
65pub type ContactObjectUrl = String;
66pub type SpecificationExtension = serde_json::Value;
67
68#[derive(Serialize, Deserialize, Clone)]
69pub struct ContactObject {
70    pub name: Option<ContactObjectName>,
71    pub email: Option<ContactObjectEmail>,
72    pub url: Option<ContactObjectUrl>,
73}
74
75pub type LicenseObjectName = String;
76pub type LicenseObjectUrl = String;
77
78#[derive(Serialize, Deserialize, Clone)]
79pub struct LicenseObject {
80    pub name: Option<LicenseObjectName>,
81    pub url: Option<LicenseObjectUrl>,
82}
83
84#[derive(Serialize, Deserialize, Clone)]
85pub struct InfoObject {
86    pub title: InfoObjectProperties,
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub description: Option<InfoObjectDescription>,
89    #[serde(rename = "termsOfService")]
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub terms_of_service: Option<InfoObjectTermsOfService>,
92    pub version: InfoObjectVersion,
93    #[serde(skip_serializing_if = "Option::is_none")]
94    pub contact: Option<ContactObject>,
95    #[serde(skip_serializing_if = "Option::is_none")]
96    pub license: Option<LicenseObject>,
97}
98
99pub type ExternalDocumentationObjectDescription = String;
100pub type ExternalDocumentationObjectUrl = String;
101
102/// ExternalDocumentationObject
103///
104/// information about external documentation
105///
106#[derive(Serialize, Deserialize, Clone)]
107pub struct ExternalDocumentationObject {
108    pub description: Option<ExternalDocumentationObjectDescription>,
109    pub url: ExternalDocumentationObjectUrl,
110}
111
112pub type ServerObjectUrl = String;
113pub type ServerObjectName = String;
114pub type ServerObjectDescription = String;
115pub type ServerObjectSummary = String;
116pub type ServerObjectVariableDefault = String;
117pub type ServerObjectVariableDescription = String;
118pub type ServerObjectVariableEnumItem = String;
119pub type ServerObjectVariableEnum = Vec<ServerObjectVariableEnumItem>;
120
121#[derive(Serialize, Deserialize, Clone)]
122pub struct ServerObjectVariable {
123    pub default: ServerObjectVariableDefault,
124    pub description: Option<ServerObjectVariableDescription>,
125    #[serde(rename = "enum")]
126    pub variable_enum: Option<ServerObjectVariableEnum>,
127}
128
129pub type ServerObjectVariables = HashMap<String, Option<serde_json::Value>>;
130
131#[derive(Serialize, Deserialize, Clone)]
132pub struct ServerObject {
133    pub url: ServerObjectUrl,
134    #[serde(skip_serializing_if = "Option::is_none")]
135    pub name: Option<ServerObjectName>,
136    #[serde(skip_serializing_if = "Option::is_none")]
137    pub description: Option<ServerObjectDescription>,
138    #[serde(skip_serializing_if = "Option::is_none")]
139    pub summary: Option<ServerObjectSummary>,
140    #[serde(skip_serializing_if = "Option::is_none")]
141    pub variables: Option<ServerObjectVariables>,
142}
143
144pub type Servers = Vec<ServerObject>;
145/// MethodObjectName
146///
147/// The cannonical name for the method. The name MUST be unique within the methods array.
148///
149pub type MethodObjectName = String;
150/// MethodObjectDescription
151///
152/// A verbose explanation of the method behavior. GitHub Flavored Markdown syntax MAY be used for rich text representation.
153///
154pub type MethodObjectDescription = String;
155/// MethodObjectSummary
156///
157/// A short summary of what the method does.
158///
159pub type MethodObjectSummary = String;
160pub type TagObjectName = String;
161pub type TagObjectDescription = String;
162
163#[derive(Serialize, Deserialize, Clone)]
164pub struct TagObject {
165    pub name: TagObjectName,
166    #[serde(skip_serializing_if = "Option::is_none")]
167    pub description: Option<TagObjectDescription>,
168    #[serde(rename = "externalDocs")]
169    #[serde(skip_serializing_if = "Option::is_none")]
170    pub external_docs: Option<ExternalDocumentationObject>,
171}
172
173#[derive(Serialize, Deserialize, Clone)]
174pub struct ReferenceObject {
175    #[serde(rename = "$ref")]
176    pub reference: String,
177}
178
179#[derive(Serialize, Deserialize, Clone)]
180#[serde(untagged)]
181pub enum TagOrReference {
182    TagObject(TagObject),
183    ReferenceObject(ReferenceObject),
184}
185
186pub type MethodObjectTags = Vec<TagOrReference>;
187
188/// MethodObjectParamStructure
189///
190/// Format the server expects the params. Defaults to 'either'.
191///
192/// # Default
193///
194/// either
195///
196#[derive(Serialize, Deserialize, Clone)]
197pub enum MethodObjectParamStructure {
198    #[serde(rename = "by-position")]
199    ByPosition,
200    #[serde(rename = "by-name")]
201    ByName,
202    #[serde(rename = "either")]
203    Either,
204}
205
206pub type ContentDescriptorObjectName = String;
207pub type ContentDescriptorObjectDescription = String;
208pub type ContentDescriptorObjectSummary = String;
209pub type Id = String;
210pub type Schema = String;
211pub type Comment = String;
212pub type Title = String;
213pub type Description = String;
214type AlwaysTrue = serde_json::Value;
215pub type ReadOnly = bool;
216pub type Examples = Vec<AlwaysTrue>;
217pub type MultipleOf = f64;
218pub type Maximum = f64;
219pub type ExclusiveMaximum = f64;
220pub type Minimum = f64;
221pub type ExclusiveMinimum = f64;
222pub type NonNegativeInteger = i64;
223pub type NonNegativeIntegerDefaultZero = i64;
224pub type Pattern = String;
225pub type SchemaArray = Vec<JSONSchema>;
226
227#[derive(Serialize, Deserialize, Clone)]
228#[serde(untagged)]
229pub enum Items {
230    JSONSchema(JSONSchema),
231    SchemaArray(SchemaArray),
232}
233
234pub type UniqueItems = bool;
235pub type StringDoaGddGA = String;
236/// StringArray
237///
238/// # Default
239///
240/// []
241///
242pub type StringArray = Vec<StringDoaGddGA>;
243/// Definitions
244///
245/// # Default
246///
247/// {}
248///
249pub type Definitions = HashMap<String, Option<serde_json::Value>>;
250/// Properties
251///
252/// # Default
253///
254/// {}
255///
256pub type Properties = HashMap<String, Option<serde_json::Value>>;
257/// PatternProperties
258///
259/// # Default
260///
261/// {}
262///
263pub type PatternProperties = HashMap<String, Option<serde_json::Value>>;
264
265#[derive(Serialize, Deserialize, Clone)]
266#[serde(untagged)]
267pub enum DependenciesSet {
268    JSONSchema(JSONSchema),
269    StringArray(StringArray),
270}
271
272pub type Dependencies = HashMap<String, Option<serde_json::Value>>;
273pub type Enum = Vec<AlwaysTrue>;
274pub type SimpleTypes = serde_json::Value;
275pub type ArrayOfSimpleTypes = Vec<SimpleTypes>;
276
277#[derive(Serialize, Deserialize, Clone)]
278#[serde(untagged)]
279pub enum Type {
280    SimpleTypes(SimpleTypes),
281    ArrayOfSimpleTypes(ArrayOfSimpleTypes),
282}
283
284pub type Format = String;
285pub type ContentMediaType = String;
286pub type ContentEncoding = String;
287
288/// JSONSchemaBoolean
289///
290/// Always valid if true. Never valid if false. Is constant.
291///
292#[derive(Serialize, Deserialize, Clone)]
293#[serde(untagged)]
294pub enum JSONSchema {
295    JsonSchemaObject(RootSchema),
296    JSONSchemaBoolean(bool),
297}
298
299pub type ContentDescriptorObjectRequired = bool;
300pub type ContentDescriptorObjectDeprecated = bool;
301
302#[derive(Serialize, Deserialize, Clone)]
303pub struct ContentDescriptorObject {
304    pub name: ContentDescriptorObjectName,
305    #[serde(skip_serializing_if = "Option::is_none")]
306    pub description: Option<ContentDescriptorObjectDescription>,
307    #[serde(skip_serializing_if = "Option::is_none")]
308    pub summary: Option<ContentDescriptorObjectSummary>,
309    pub schema: JSONSchema,
310    #[serde(skip_serializing_if = "Option::is_none")]
311    pub required: Option<ContentDescriptorObjectRequired>,
312    #[serde(skip_serializing_if = "Option::is_none")]
313    pub deprecated: Option<ContentDescriptorObjectDeprecated>,
314}
315
316#[derive(Serialize, Deserialize, Clone)]
317#[serde(untagged)]
318pub enum ContentDescriptorOrReference {
319    ContentDescriptorObject(ContentDescriptorObject),
320    ReferenceObject(ReferenceObject),
321}
322
323pub type MethodObjectParams = Vec<ContentDescriptorOrReference>;
324
325/// ErrorObjectCode
326///
327/// A Number that indicates the error type that occurred. This MUST be an integer. The error codes from and including -32768 to -32000 are reserved for pre-defined errors. These pre-defined errors SHOULD be assumed to be returned from any JSON-RPC api.
328///
329pub type ErrorObjectCode = i64;
330/// ErrorObjectMessage
331///
332/// A String providing a short description of the error. The message SHOULD be limited to a concise single sentence.
333///
334pub type ErrorObjectMessage = String;
335/// ErrorObjectData
336///
337/// A Primitive or Structured value that contains additional information about the error. This may be omitted. The value of this member is defined by the Server (e.g. detailed error information, nested errors etc.).
338///
339pub type ErrorObjectData = serde_json::Value;
340
341/// ErrorObject
342///
343/// Defines an application level error.
344///
345#[derive(Serialize, Deserialize, Clone)]
346pub struct ErrorObject {
347    pub code: ErrorObjectCode,
348    pub message: ErrorObjectMessage,
349    #[serde(skip_serializing_if = "Option::is_none")]
350    pub data: Option<ErrorObjectData>,
351}
352
353#[derive(Serialize, Deserialize, Clone)]
354#[serde(untagged)]
355pub enum ErrorOrReference {
356    ErrorObject(ErrorObject),
357    ReferenceObject(ReferenceObject),
358}
359
360/// MethodObjectErrors
361///
362/// Defines an application level error.
363///
364pub type MethodObjectErrors = Vec<ErrorOrReference>;
365pub type LinkObjectName = String;
366pub type LinkObjectSummary = String;
367pub type LinkObjectMethod = String;
368pub type LinkObjectDescription = String;
369pub type LinkObjectParams = serde_json::Value;
370
371#[derive(Serialize, Deserialize, Clone)]
372pub struct LinkObjectServer {
373    pub url: ServerObjectUrl,
374    #[serde(skip_serializing_if = "Option::is_none")]
375    pub name: Option<ServerObjectName>,
376    #[serde(skip_serializing_if = "Option::is_none")]
377    pub description: Option<ServerObjectDescription>,
378    #[serde(skip_serializing_if = "Option::is_none")]
379    pub summary: Option<ServerObjectSummary>,
380    #[serde(skip_serializing_if = "Option::is_none")]
381    pub variables: Option<ServerObjectVariables>,
382}
383
384#[derive(Serialize, Deserialize, Clone)]
385pub struct LinkObject {
386    #[serde(skip_serializing_if = "Option::is_none")]
387    pub name: Option<LinkObjectName>,
388    #[serde(skip_serializing_if = "Option::is_none")]
389    pub summary: Option<LinkObjectSummary>,
390    #[serde(skip_serializing_if = "Option::is_none")]
391    pub method: Option<LinkObjectMethod>,
392    #[serde(skip_serializing_if = "Option::is_none")]
393    pub description: Option<LinkObjectDescription>,
394    #[serde(skip_serializing_if = "Option::is_none")]
395    pub params: Option<LinkObjectParams>,
396    #[serde(skip_serializing_if = "Option::is_none")]
397    pub server: Option<LinkObjectServer>,
398}
399
400#[derive(Serialize, Deserialize, Clone)]
401#[serde(untagged)]
402pub enum LinkOrReference {
403    LinkObject(LinkObject),
404    ReferenceObject(ReferenceObject),
405}
406
407pub type MethodObjectLinks = Vec<LinkOrReference>;
408pub type ExamplePairingObjectName = String;
409pub type ExamplePairingObjectDescription = String;
410pub type ExampleObjectSummary = String;
411pub type ExampleObjectValue = serde_json::Value;
412pub type ExampleObjectDescription = String;
413pub type ExampleObjectName = String;
414
415#[derive(Serialize, Deserialize, Clone)]
416pub struct ExampleObject {
417    #[serde(skip_serializing_if = "Option::is_none")]
418    pub summary: Option<ExampleObjectSummary>,
419    pub value: ExampleObjectValue,
420    #[serde(skip_serializing_if = "Option::is_none")]
421    pub description: Option<ExampleObjectDescription>,
422    pub name: ExampleObjectName,
423}
424
425#[derive(Serialize, Deserialize, Clone)]
426#[serde(untagged)]
427pub enum ExampleOrReference {
428    ExampleObject(ExampleObject),
429    ReferenceObject(ReferenceObject),
430}
431
432pub type ExamplePairingObjectParams = Vec<ExampleOrReference>;
433
434#[derive(Serialize, Deserialize, Clone)]
435#[serde(untagged)]
436pub enum ExamplePairingObjectResult {
437    ExampleObject(ExampleObject),
438    ReferenceObject(ReferenceObject),
439}
440
441#[derive(Serialize, Deserialize, Clone)]
442pub struct ExamplePairingObject {
443    pub name: ExamplePairingObjectName,
444    #[serde(skip_serializing_if = "Option::is_none")]
445    pub description: Option<ExamplePairingObjectDescription>,
446    pub params: ExamplePairingObjectParams,
447    pub result: ExamplePairingObjectResult,
448}
449
450#[derive(Serialize, Deserialize, Clone)]
451#[serde(untagged)]
452pub enum ExamplePairingOrReference {
453    ExampleObject(ExampleObject),
454    ReferenceObject(ReferenceObject),
455}
456
457pub type MethodObjectExamples = Vec<ExamplePairingOrReference>;
458pub type MethodObjectDeprecated = bool;
459
460#[derive(Serialize, Deserialize, Clone)]
461pub struct MethodObject {
462    pub name: MethodObjectName,
463    #[serde(skip_serializing_if = "Option::is_none")]
464    pub description: Option<MethodObjectDescription>,
465    #[serde(skip_serializing_if = "Option::is_none")]
466    pub summary: Option<MethodObjectSummary>,
467    #[serde(skip_serializing_if = "Option::is_none")]
468    pub servers: Option<Servers>,
469    #[serde(skip_serializing_if = "Option::is_none")]
470    pub tags: Option<MethodObjectTags>,
471    #[serde(rename = "paramStructure")]
472    #[serde(skip_serializing_if = "Option::is_none")]
473    pub param_structure: Option<MethodObjectParamStructure>,
474    pub params: MethodObjectParams,
475    pub result: ContentDescriptorOrReference,
476    #[serde(skip_serializing_if = "Option::is_none")]
477    pub errors: Option<MethodObjectErrors>,
478    #[serde(skip_serializing_if = "Option::is_none")]
479    pub links: Option<MethodObjectLinks>,
480    #[serde(skip_serializing_if = "Option::is_none")]
481    pub examples: Option<MethodObjectExamples>,
482    #[serde(skip_serializing_if = "Option::is_none")]
483    pub deprecated: Option<MethodObjectDeprecated>,
484    #[serde(skip_serializing_if = "Option::is_none")]
485    #[serde(rename = "externalDocs")]
486    pub external_docs: Option<ExternalDocumentationObject>,
487}
488
489pub type Methods = Vec<MethodObject>;
490pub type SchemaComponents = HashMap<String, Option<serde_json::Value>>;
491pub type LinkComponents = HashMap<String, Option<serde_json::Value>>;
492pub type ErrorComponents = HashMap<String, Option<serde_json::Value>>;
493pub type ExampleComponents = HashMap<String, Option<serde_json::Value>>;
494pub type ExamplePairingComponents = HashMap<String, Option<serde_json::Value>>;
495pub type ContentDescriptorComponents = HashMap<String, Option<serde_json::Value>>;
496pub type TagComponents = HashMap<String, Option<serde_json::Value>>;
497
498#[derive(Serialize, Deserialize, Clone)]
499pub struct Components {
500    #[serde(skip_serializing_if = "Option::is_none")]
501    pub schemas: Option<SchemaComponents>,
502    #[serde(skip_serializing_if = "Option::is_none")]
503    pub links: Option<LinkComponents>,
504    #[serde(skip_serializing_if = "Option::is_none")]
505    pub errors: Option<ErrorComponents>,
506    #[serde(skip_serializing_if = "Option::is_none")]
507    pub examples: Option<ExampleComponents>,
508    #[serde(rename = "examplePairings")]
509    pub example_pairings: Option<ExamplePairingComponents>,
510    #[serde(rename = "contentDescriptors")]
511    #[serde(skip_serializing_if = "Option::is_none")]
512    pub content_descriptors: Option<ContentDescriptorComponents>,
513    #[serde(skip_serializing_if = "Option::is_none")]
514    pub tags: Option<TagComponents>,
515}
516
517#[derive(Serialize, Deserialize, Clone)]
518pub struct OpenrpcDocument {
519    pub openrpc: Openrpc,
520    pub info: InfoObject,
521    #[serde(rename = "externalDocs")]
522    #[serde(skip_serializing_if = "Option::is_none")]
523    pub external_docs: Option<ExternalDocumentationObject>,
524    #[serde(skip_serializing_if = "Option::is_none")]
525    pub servers: Option<Servers>,
526    pub methods: Methods,
527    #[serde(skip_serializing_if = "Option::is_none")]
528    pub components: Option<Components>,
529}
530
531impl Default for OpenrpcDocument {
532    fn default() -> Self {
533        OpenrpcDocument {
534            openrpc: Openrpc::V26,
535            info: InfoObject {
536                title: "".to_string(),
537                description: None,
538                terms_of_service: None,
539                version: "".to_string(),
540                contact: None,
541                license: None,
542            },
543            external_docs: None,
544            servers: None,
545            methods: vec![],
546            components: None,
547        }
548    }
549}
550
551impl OpenrpcDocument {
552    pub fn set_info(mut self, info: InfoObject) -> Self {
553        self.info = info;
554        self
555    }
556    pub fn add_object_method(&mut self, method: MethodObject) {
557        self.methods.push(method)
558    }
559}
560
561impl ContentDescriptorOrReference {
562    pub fn new_content_descriptor<T: ?Sized + JsonSchema>(
563        name: ContactObjectName,
564        description: Option<Description>,
565    ) -> Self {
566        let mut setting = SchemaSettings::draft07();
567        setting.inline_subschemas = true;
568        let schema = schemars::gen::SchemaGenerator::new(setting).into_root_schema_for::<T>();
569        let json_schema = JSONSchema::JsonSchemaObject(schema);
570        ContentDescriptorOrReference::ContentDescriptorObject(ContentDescriptorObject {
571            name,
572            description,
573            summary: None,
574            schema: json_schema,
575            required: None,
576            deprecated: None,
577        })
578    }
579}
580
581impl MethodObject {
582    pub fn new(name: MethodObjectName, description: Option<Description>) -> Self {
583        Self {
584            name,
585            description,
586            summary: None,
587            servers: None,
588            tags: None,
589            param_structure: None,
590            params: vec![],
591            result: ContentDescriptorOrReference::ReferenceObject(ReferenceObject {
592                reference: "".to_string(),
593            }),
594            errors: None,
595            links: None,
596            examples: None,
597            deprecated: None,
598            external_docs: None,
599        }
600    }
601}
602
603#[cfg(test)]
604mod tests {
605    use super::*;
606    #[derive(JsonSchema)]
607    pub struct MyType([u8; 8]);
608
609    #[derive(JsonSchema)]
610    pub struct MyParam {
611        pub my_int: i32,
612        pub my_bool: bool,
613        pub my_type: Box<MyType>,
614    }
615
616    #[derive(JsonSchema)]
617    pub struct MyRet {
618        pub success: Box<bool>,
619    }
620
621    #[test]
622    fn test_openrpc_document() {
623        let mut document = OpenrpcDocument::default();
624        let mut method = MethodObject::new("method1".to_string(), None);
625        let param = ContentDescriptorOrReference::new_content_descriptor::<MyParam>(
626            "first_param".to_string(),
627            Some("no desc".to_string()),
628        );
629        method.params.push(param);
630        method.result =
631            ContentDescriptorOrReference::new_content_descriptor::<MyRet>("ret".to_string(), None);
632        document.add_object_method(method);
633        let j = serde_json::to_string_pretty(&document).unwrap();
634        println!("{}", j);
635    }
636}