If your data source retrieves data from an official, well-defined API, you can simplify your data source configuration by only asking for the relevant data, such as the API token. However, if the user should be able to access data from any given HTTP endpoint, you probably want to let them configure things like authentication headers and query parameters to fit their needs. In this post, I’ll explain how you can build a configurable HTTP-based backend data source.
Note: This post requires version 0.106.0 or greater of Grafana SDK for Go.
Creating a config editor for all possible HTTP options is a lot work. Instead of doing it yourself, consider using the DataSourceHTTPSettings component from the @grafana/ui
package:
import { DataSourceHttpSettings } from '@grafana/ui';
<DataSourceHttpSettings
defaultUrl="http://localhost:8080"
dataSourceConfig={options}
onChange={onOptionsChange}
/>
In the following example, you can see how this can simplify your config editor to a few lines of code:
import React from 'react';
import { DataSourceHttpSettings } from '@grafana/ui';
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
import { MyDataSourceOptions } from './types';
interface Props extends DataSourcePluginOptionsEditorProps<MyDataSourceOptions> {}
export const ConfigEditor = ({ options, onOptionsChange }: Props) => {
return (
<DataSourceHttpSettings defaultUrl="http://localhost:8080" dataSourceConfig={options} onChange={onOptionsChange} />
);
};
Here’s what your users will see when they configure your data source:
The DataSourceHttpSettings
component lets the user configure the properties in the instance settings, including the jsonData
, and makes it available to our backend. Pretty neat!
The next step is to actually use the user-defined HTTP configuration when you create the requests on the backend. The httpclient
package from the Go SDK is a useful wrapper that lets us construct a http.Client
based on the data source instance settings:
package plugin
import (
"context"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
)
type SampleDatasource struct {
settings backend.DataSourceInstanceSettings
httpClient *http.Client
}
func NewSampleDatasource(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
httpOptions, err := settings.HTTPClientOptions()
if err != nil {
return nil, err
}
client, err := httpclient.New(httpOptions)
if err != nil {
return nil, err
}
return &SampleDatasource{
settings: settings,
httpClient: client,
}, nil
}
Note: By adding the
http.Client
in the data source struct, we can reuse the client object across queries. This lets the HTTP client reuse open connections rather than having to create new ones for each query.
For example, here’s how you can use the HTTP client to perform a data source health check:
func (d *SampleDatasource) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
httpReq, err := http.NewRequestWithContext(ctx, "GET", d.settings.URL, nil)
if err != nil {
return nil, err
}
resp, err := d.httpClient.Do(httpReq)
if err != nil {
return nil, err
}
if resp.StatusCode != 200 {
return &backend.CheckHealthResult{
Status: backend.HealthStatusError,
Message: "Something went wrong: " + resp.Status,
}, nil
}
return &backend.CheckHealthResult{
Status: backend.HealthStatusOk,
Message: "Success",
}, nil
}
Combine the DataSourceHttpSettings
component in @grafana/ui
together with the httpclient
from the Go SDK to effortlessly configure and make API requests based on user-defined HTTP configuration.