How to add a query multiplexer/router for your datasource

Normally you implement the QueryData method in your backend plugin. But what if you need to support different kinds of queries, e.g. metrics, logs, traces etc? That’s where the usage of a query multiplexer/router comes handy.

The requirement is that you need to populate the queryType property of your query model client side, see DataQuery interface.

With queryType populated in queries and sent to your backend plugin below is an example of how you would use the datasource.QueryTypeMux to multiplex/route different query types to separate query handlers. Each query handler can then for example json.Unmarshal each query JSON field in DataQuery to a certain Go struct.

package mydatasource

import (
	"context"

	"github.com/grafana/grafana-plugin-sdk-go/backend"
	"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
)

type MyDatasource struct {
	queryHandler backend.QueryDataHandler
}

func New() *MyDatasource {
	ds := &MyDatasource{}
	queryTypeMux := datasource.NewQueryTypeMux()
	queryTypeMux.HandleFunc("metrics", ds.handleMetricsQuery)
	queryTypeMux.HandleFunc("logs", ds.handleLogsQuery)
	queryTypeMux.HandleFunc("traces", ds.handleTracesQuery)
	queryTypeMux.HandleFunc("", ds.handleQueryFallback)
	ds.queryHandler := queryTypeMux
	return ds
}

func (d *MyDatasource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
	return d.queryHandler.QueryData(ctx, req)
}

// handleMetricsQuery handle queries of query type "metrics".
// All queries in backend.QueryDataRequest is guaranteed to only 
// include queries with queryType "metrics".
func (d *MyDatasource) handleMetricsQuery(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
	// implementation...
}

// handleLogsQuery handle queries of query type "logs".
// All queries in backend.QueryDataRequest is guaranteed to only 
// include queries with queryType "logs".
func (d *MyDatasource) handleLogsQuery(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
	// implementation...
}

// handleTracesQuery handle queries of query type "logs".
// All queries in backend.QueryDataRequest is guaranteed to only 
// include queries with queryType "traces".
func (d *MyDatasource) handleTracesQuery(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
	// implementation...
}

// handleQueryFallback handle queries without a matching query type handler registered.
func (d *MyDatasource) handleQueryFallback(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
	// implementation...
}

One example of using QueryTypeMux can be found for the builtin Grafana Azure Monitor datasource, however a bit more advanced usage: