# Add resource handler for data source plugins

You can add a resource handler to your data source backend to extend the Grafana HTTP API with your own data source-specific routes. This guide explains why you may want to add [resource](https://grafana.com/developers/plugin-tools/key-concepts/backend-plugins.md#resources) handlers and some common ways for doing so.

## Uses of resource handlers[​](#uses-of-resource-handlers "Direct link to Uses of resource handlers")

The primary way for a data source to retrieve data from a backend is through the [query method](https://grafana.com/developers/plugin-tools/tutorials/build-a-data-source-plugin.md#3-implement-your-query-editor). But sometimes your data source needs to request data on demand; for example, to offer auto-completion automatically inside the data source’s query editor.

Resource handlers are also useful for building control panels that allow the user to write back to the data source. For example, you could add a resource handler to update the state of an IoT device.

## Implement the resource handler interface[​](#implement-the-resource-handler-interface "Direct link to Implement the resource handler interface")

To add a resource handler to your plugin backend component, you need to implement the `backend.CallResourceHandler` interface.

There are two ways you can implement this in your plugin, [using the `httpadapter` package](#using-the-httpadapter-package) or [manually implementing it](#manually-implementing-backendcallresourcehandler) in your plugin.

### Using the `httpadapter` package[​](#using-the-httpadapter-package "Direct link to using-the-httpadapter-package")

The [`httpadapter`](https://pkg.go.dev/github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter) package provided by the [Grafana Plugin SDK for Go](https://grafana.com/developers/plugin-tools/key-concepts/backend-plugins/grafana-plugin-sdk-for-go.md) is the recommended way for handling resources. This package provides support for handling resource calls using using the [`http.Handler`](https://pkg.go.dev/net/http#Handler) interface and allows responding to HTTP requests in a more Go-agnostic way and makes it easier to support multiple routes and methods (GET, POST etc).

Using [`http.Handler`](https://pkg.go.dev/net/http#Handler) allows you to also use Go’s built-in router functionality called [`ServeMux`](https://pkg.go.dev/net/http#ServeMux) or your preferred HTTP router library (for example, [`gorilla/mux`](https://github.com/gorilla/mux)).

note

Go 1.22 [includes routing enhancement](https://go.dev/blog/routing-enhancements) that adds support for method matching and wildcards using the [`ServeMux`](https://pkg.go.dev/net/http#ServeMux).

In the following example we demonstrate using the `httpadapter` package, `ServeMux` and `http.Handler` to add support for retrieving namespaces (`/namespaces`), projects (`/projects`) and updating the state of some device (`/device`) :

```go
package myplugin

import (
  "context"
  "net/http"

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

type MyPlugin struct {
  resourceHandler backend.CallResourceHandler
}

func New() *MyPlugin {
  p := &MyPlugin{}
  mux := http.NewServeMux()
  mux.HandleFunc("/namespaces", p.handleNamespaces)
  mux.HandleFunc("/projects", p.handleProjects)
  p.resourceHandler := httpadapter.New(mux)
  return p
}

func (p *MyPlugin) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
  return p.resourceHandler.CallResource(ctx, req, sender)
}

func (p *MyPlugin) handleNamespaces(rw http.ResponseWriter, req *http.Request) {
  rw.Header().Add("Content-Type", "application/json")
  _, err := rw.Write([]byte(`{ "namespaces": ["ns-1", "ns-2"] }`))
  if err != nil {
    return
  }
  rw.WriteHeader(http.StatusOK)
}

func (p *MyPlugin) handleProjects(rw http.ResponseWriter, req *http.Request) {
  rw.Header().Add("Content-Type", "application/json")
  _, err := rw.Write([]byte(`{ "projects": ["project-1", "project-2"] }`))
  if err != nil {
    return
  }
  rw.WriteHeader(http.StatusOK)
}

```

#### Accessing the plugin context[​](#accessing-the-plugin-context "Direct link to Accessing the plugin context")

You can use the [backend.PluginConfigFromContext](https://pkg.go.dev/github.com/grafana/grafana-plugin-sdk-go/backend#PluginConfigFromContext) function to access [backend.PluginContext](https://pkg.go.dev/github.com/grafana/grafana-plugin-sdk-go/backend#PluginContext). This holds contextual information about a plugin request, such as the user performing the request:

```go
func (p *MyPlugin) handleSomeRoute(rw http.ResponseWriter, req *http.Request) {
	pCtx := backend.PluginConfigFromContext(req.Context())
	bytes, err := json.Marshal(pCtx.User)
	if err != nil {
		return
	}

	rw.Header().Add("Content-Type", "application/json")
	_, err := rw.Write(bytes)
	if err != nil {
		return
	}
	rw.WriteHeader(http.StatusOK)
}

```

### Manually implementing `backend.CallResourceHandler`[​](#manually-implementing-backendcallresourcehandler "Direct link to manually-implementing-backendcallresourcehandler")

Manually implementing the `backend.CallResourceHandler` interface might be enough for the basic needs. To support a couple of different routes retrieving data you can use a switch with the `req.Path`:

```go
func (p *MyPlugin) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
	switch req.Path {
	case "namespaces":
		return sender.Send(&backend.CallResourceResponse{
			Status: http.StatusOK,
			Body:   []byte(`{ "namespaces": ["ns-1", "ns-2"] }`),
		})
	case "projects":
		return sender.Send(&backend.CallResourceResponse{
			Status: http.StatusOK,
			Body:   []byte(`{ "projects": ["project-1", "project-2"] }`),
		})
	default:
		return sender.Send(&backend.CallResourceResponse{
			Status: http.StatusNotFound,
		})
	}
}

```

## Accessing datasource resources[​](#accessing-datasource-resources "Direct link to Accessing datasource resources")

Once implemented you can access the resources using the Grafana HTTP API and from the frontend.

### Using the Grafana HTTP API[​](#using-the-grafana-http-api "Direct link to Using the Grafana HTTP API")

You can access the resources through the Grafana HTTP API by using the endpoint, `http://<GRAFANA_HOSTNAME>:<PORT>/api/datasources/uid/<DATASOURCE_UID>/resources{/<RESOURCE>}`. The `DATASOURCE_UID` is the data source unique identifier (UID) that uniquely identifies your data source and the `RESOURCE` depends on how the resource handler is implemented and what resources (routes) are supported.

With the above example you can access the following resources:

* HTTP GET `http://<GRAFANA_HOSTNAME>:<PORT>/api/datasources/uid/<DATASOURCE_UID>/resources/namespaces`
* HTTP GET `http://<GRAFANA_HOSTNAME>:<PORT>/api/datasources/uid/<DATASOURCE_UID>/resources/projects`

tip

To verify the data source UID, you can enter `window.grafanaBootData.settings.datasources` in your browser's developer tools console, to list all the configured data sources in your Grafana instance.

### From the frontend[​](#from-the-frontend "Direct link to From the frontend")

You can query your resources using the `getResource` and `postResource` helpers from the `DataSourceWithBackend` class. To provide a nicer and more convenient API for your components it's recommended to extend your datasource class and instance with functions for each route as shown in the following example:

```typescript
export class MyDataSource extends DataSourceWithBackend<MyQuery, MyDataSourceOptions> {
  constructor(instanceSettings: DataSourceInstanceSettings<MyDataSourceOptions>) {
    super(instanceSettings);
  }

  getNamespaces(): Promise<NamespacesResponse> {
    return this.getResource('/namespaces');
  }

  getProjects(): Promise<ProjectsResponse> {
    return this.getResource('/projects');
  }
}

```

For example, in your query editor component, you can access the data source instance from the `props` object and use `getNamespaces` to send a HTTP GET request to `http://<GRAFANA_HOSTNAME>:<PORT>/api/datasources/uid/<DATASOURCE_UID>/resources/namespaces`:

```typescript
const namespaces = await props.datasource.getNamespaces();

```

## Additional examples[​](#additional-examples "Direct link to Additional examples")

Some other examples of using resource handlers and the [`httpadapter`](https://pkg.go.dev/github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter) package:

* The [datasource-basic](https://github.com/grafana/grafana-plugin-examples/tree/main/examples/datasource-basic) example.
* Grafana's built-in TestData datasource, [create resource handler](https://github.com/grafana/grafana/blob/5687243d0b3bad06c4da809f925cfdf3d32c5a16/pkg/tsdb/grafana-testdata-datasource/testdata.go#L45) and [register routes](https://github.com/grafana/grafana/blob/5687243d0b3bad06c4da809f925cfdf3d32c5a16/pkg/tsdb/grafana-testdata-datasource/resource_handler.go#L17-L28).
