pallet_schemas_rpc/
lib.rs

1// Strong Documentation Lints
2#![deny(
3	rustdoc::broken_intra_doc_links,
4	rustdoc::missing_crate_level_docs,
5	rustdoc::invalid_codeblock_attributes,
6	missing_docs
7)]
8
9//! Custom APIs for [Schemas](../pallet_schemas/index.html)
10
11use common_helpers::{avro, rpc::map_rpc_result};
12use common_primitives::schema::*;
13use jsonrpsee::{
14	core::{async_trait, RpcResult},
15	proc_macros::rpc,
16	types::error::ErrorObject,
17};
18use pallet_schemas_runtime_api::SchemasRuntimeApi;
19use sp_api::ProvideRuntimeApi;
20use sp_blockchain::HeaderBackend;
21use sp_runtime::traits::Block as BlockT;
22extern crate alloc;
23use alloc::{sync::Arc, vec::Vec};
24
25#[cfg(test)]
26mod tests;
27
28/// Errors that occur on the client RPC
29pub enum SchemaRpcError {
30	/// No schema was found for the given id.
31	SchemaNotFound,
32	/// Failed to fetch latest schema.
33	SchemaSearchError,
34	/// Schema model did not validate
35	SchemaValidationError,
36}
37
38impl From<SchemaRpcError> for i32 {
39	fn from(e: SchemaRpcError) -> i32 {
40		match e {
41			SchemaRpcError::SchemaNotFound => 1,
42			SchemaRpcError::SchemaSearchError => 2,
43			SchemaRpcError::SchemaValidationError => 3,
44		}
45	}
46}
47
48/// Frequency Schema Custom RPC API
49#[rpc(client, server)]
50pub trait SchemasApi<BlockHash> {
51	/// retrieving schema by schema id
52	#[method(name = "schemas_getBySchemaId")]
53	fn get_by_schema_id(&self, schema_id: SchemaId) -> RpcResult<Option<SchemaResponse>>;
54
55	/// validates a schema model and returns `true` if the model is correct.
56	#[method(name = "schemas_checkSchemaValidity")]
57	fn check_schema_validity(&self, model: Vec<u8>, at: Option<BlockHash>) -> RpcResult<bool>;
58
59	/// returns an array of schema versions
60	#[method(name = "schemas_getVersions")]
61	fn get_versions(&self, schema_name: String) -> RpcResult<Option<Vec<SchemaVersionResponse>>>;
62}
63
64/// The client handler for the API used by Frequency Service RPC with `jsonrpsee`
65pub struct SchemasHandler<C, M> {
66	client: Arc<C>,
67	_marker: std::marker::PhantomData<M>,
68}
69
70impl<C, M> SchemasHandler<C, M> {
71	/// Create new instance with the given reference to the client.
72	pub fn new(client: Arc<C>) -> Self {
73		Self { client, _marker: Default::default() }
74	}
75}
76
77#[async_trait]
78impl<C, Block> SchemasApiServer<<Block as BlockT>::Hash> for SchemasHandler<C, Block>
79where
80	Block: BlockT,
81	C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,
82	C::Api: SchemasRuntimeApi<Block>,
83{
84	fn check_schema_validity(
85		&self,
86		model: Vec<u8>,
87		_at: Option<<Block as BlockT>::Hash>,
88	) -> RpcResult<bool> {
89		let validated_schema = avro::validate_raw_avro_schema(&model);
90		match validated_schema {
91			Ok(_) => Ok(true),
92			Err(e) => Err(ErrorObject::owned(
93				SchemaRpcError::SchemaValidationError.into(),
94				"Unable to validate schema",
95				Some(format!("{e:?}")),
96			)),
97		}
98	}
99
100	fn get_by_schema_id(&self, schema_id: SchemaId) -> RpcResult<Option<SchemaResponse>> {
101		let api = self.client.runtime_api();
102		let at = self.client.info().best_hash;
103		let schema_api_result = api.get_by_schema_id(at, schema_id);
104		map_rpc_result(schema_api_result)
105	}
106
107	fn get_versions(&self, schema_name: String) -> RpcResult<Option<Vec<SchemaVersionResponse>>> {
108		let api = self.client.runtime_api();
109		let at = self.client.info().best_hash;
110		let schema_api_result = api.get_schema_versions_by_name(at, schema_name.into_bytes());
111		map_rpc_result(schema_api_result)
112	}
113}