Trait grafana_plugin_sdk::backend::DataService
source · pub trait DataService {
type Query: DeserializeOwned + Send + Sync;
type QueryError: DataQueryError;
type Stream: Stream<Item = Result<DataResponse, Self::QueryError>> + Send;
// Required method
fn query_data<'life0, 'async_trait>(
&'life0 self,
request: QueryDataRequest<Self::Query>
) -> Pin<Box<dyn Future<Output = Self::Stream> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
}
Expand description
Used to respond for requests for data from datasources and app plugins.
Datasource plugins will usually want to implement this trait to perform the bulk of their processing.
Example
use futures_util::stream::FuturesOrdered;
use grafana_plugin_sdk::{backend, data, prelude::*};
use thiserror::Error;
struct MyPlugin;
/// An error that may occur during a query.
///
/// This must store the `ref_id` of the query so that Grafana can line it up.
#[derive(Debug, Error)]
#[error("Error querying backend for query {ref_id}: {source}")]
struct QueryError {
source: data::Error,
ref_id: String,
}
impl backend::DataQueryError for QueryError {
fn ref_id(self) -> String {
self.ref_id
}
}
#[backend::async_trait]
impl backend::DataService for MyPlugin {
/// The type of JSON data sent from Grafana to our backend plugin.
///
/// This will correspond to the `TQuery` type parameter of the frontend
/// datasource.
///
/// We can use `serde_json::Value` if we want to accept any JSON.
type Query = serde_json::Value;
/// The type of error that could be returned by an individual query.
type QueryError = QueryError;
/// The type of iterator we're returning.
///
/// In general the concrete type will be impossible to name in advance,
/// so the `backend::BoxDataResponseStream` type alias will be useful.
type Stream = backend::BoxDataResponseStream<Self::QueryError>;
/// Respond to a request for data from Grafana.
///
/// This request will contain zero or more queries, as well as information
/// about the datasource instance on behalf of which this request is made,
/// such as address, credentials, etc.
///
/// Our plugin must respond to each query and return an iterator of `DataResponse`s,
/// which themselves can contain zero or more `Frame`s.
async fn query_data(&self, request: backend::QueryDataRequest<Self::Query>) -> Self::Stream {
Box::pin(
request
.queries
.into_iter()
.map(|x| async {
// Here we create a single response Frame for each query.
// Frames can be created from iterators of fields using [`IntoFrame`].
Ok(backend::DataResponse::new(
x.ref_id.clone(),
// Return zero or more frames.
// A real implementation would fetch this data from a database
// or something.
vec![[
[1_u32, 2, 3].into_field("x"),
["a", "b", "c"].into_field("y"),
]
.into_frame("foo")
.check()
.map_err(|source| QueryError {
ref_id: x.ref_id,
source,
})?],
))
})
.collect::<FuturesOrdered<_>>(),
)
}
}
Required Associated Types§
sourcetype Query: DeserializeOwned + Send + Sync
type Query: DeserializeOwned + Send + Sync
The type of the JSON query sent from Grafana to the plugin.
sourcetype QueryError: DataQueryError
type QueryError: DataQueryError
The error type that can be returned by individual queries.
This must implement DataQueryError
, which allows the SDK to
align queries up with any failed requests.
sourcetype Stream: Stream<Item = Result<DataResponse, Self::QueryError>> + Send
type Stream: Stream<Item = Result<DataResponse, Self::QueryError>> + Send
The type of stream returned by the query_data
method.
This will generally be impossible to name directly, so returning the
BoxDataResponseStream
type alias will probably be more convenient.
Required Methods§
sourcefn query_data<'life0, 'async_trait>(
&'life0 self,
request: QueryDataRequest<Self::Query>
) -> Pin<Box<dyn Future<Output = Self::Stream> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn query_data<'life0, 'async_trait>(
&'life0 self,
request: QueryDataRequest<Self::Query>
) -> Pin<Box<dyn Future<Output = Self::Stream> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Query data for an input request.
The request will contain zero or more queries, as well as information about the
origin of the queries (such as the datasource instance) in the plugin_context
field.