A backend component for an app plugin allows you to extend the app plugin for additional functionality such as custom authentication methods and integration with other services.
The following are typical use cases for backend components in app plugins:
Install the following prerequisites before adding a backend component:
Create a new app pluginâThe Grafana create-plugin tool is a CLI application that simplifies Grafana plugin development, so that you can focus on code. The tool scaffolds a starter plugin, all the required configuration, and a development environment using Docker Compose for you.
In a new directory, create a plugin from a template using the create-plugin tool. When prompted for the kind of plugin, select app and answer yes to "Do you want a backend part of your plugin?":
npx @grafana/create-plugin@latest
Go to the directory of your newly created plugin:
Install the dependencies:
Build the plugin frontend:
In a new terminal window, build the plugin backend:
Start Grafana:
Open Grafana, by default http://localhost:3000, and then go to Administration > Plugins. Make sure that your app plugin is there.
You can also verify that Grafana has discovered the plugin by checking the logs:
INFO[01-01|12:00:00] Plugin registered logger=plugin.loader pluginID=<your-plugin>
Anatomy of a backend pluginâ
The folders and files used to build the backend for the app are:
file/folder descriptionMagefile.go
Itâs not a requirement to use mage build files, but we strongly recommend using them so that you can use the build targets provided by the plugin SDK. /go.mod
Go modules dependencies. /src/plugin.json
A JSON file describing the plugin. /pkg/main.go
Starting point of the plugin binary. The plugin.json fileâ
The plugin.json
file is required for all plugins. When building a backend plugin, pay attention especially to these properties:
backend
Set to true
for backend plugins. This tells Grafana that it should start a binary when loading the plugin. executable
This is the name of the executable that Grafana expects to start. Refer to plugin.json reference for details. alerting
If your backend data source supports alerting, set to true
. Requires backend
to be set to true
. Add authentication to your app pluginâ
To learn more about adding authentication to your app plugin (for example, to call a custom backend or third-party API) and handling secrets, refer to Add authentication for app plugins.
Access app settingsâSettings are part of the AppInstanceSettings
struct. They are passed to the app plugin constructor as the second argument. For example:
src/app.go
func NewApp(ctx context.Context, settings backend.AppInstanceSettings) (instancemgmt.Instance, error) {
jsonData := settings.JSONData
secureJsonData := settings.DecryptedSecureJSONData
}
You can also get the settings from a request Context
:
src/resources.go
func (a *App) handleMyRequest(w http.ResponseWriter, req *http.Request) {
pluginConfig := backend.PluginConfigFromContext(req.Context())
jsonData := pluginConfig.AppInstanceSettings.JSONData
}
Add a custom endpoint to your app pluginâ
Here's how to add a ServeMux
or CallResource
endpoint to your app plugin.
Your scaffolded app plugin already has a default CallResource
that uses ServeMux
. It looks like this:
app.go
type App struct {
backend.CallResourceHandler
}
func NewApp(_ context.Context, _ backend.AppInstanceSettings) (instancemgmt.Instance, error) {
var app App
mux := http.NewServeMux()
app.registerRoutes(mux)
app.CallResourceHandler = httpadapter.New(mux)
return &app, nil
}
Now you can add custom endpoints to your app plugin.
The scaffolded code already contains a resources.go
file with the registerRoutes
function.
resources.go
func (a *App) registerRoutes(mux *http.ServeMux) {
mux.HandleFunc("/myCustomEndpoint", a.handleMyCustomEndpoint)
}
func (a *App) handleMyCustomEndpoint(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("my custom response"))
w.WriteHeader(http.StatusOK)
}
CallResourceâ
You can also add custom endpoints to your app plugin by adding a CallResource
handler to your backend component directly. You must implement the logic to handle multiple requests.
app.go
func (a *App) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
switch req.Path {
case "myCustomEndpoint":
sender.Send(&backend.CallResourceResponse{
Status: http.StatusOK,
Body: []byte("my custom response"),
})
default:
return sender.Send(&backend.CallResourceResponse{
Status: http.StatusNotFound,
})
}
return nil
}
You can also see the data sources documentation on resource handler which you can also apply to your app plugin.
Call your custom endpoint from frontend codeâTo call your custom endpoint from frontend code, you can use the fetch
function from getBackendSrv
. For example:
import { getBackendSrv } from '@grafana/runtime';
import { lastValueFrom } from 'rxjs';
function getMyCustomEndpoint() {
const response = await getBackendSrv().fetch({
url: '/api/plugins/${PLUGIN_ID}/myCustomEndpoint',
});
return await lastValueFrom(response);
}
Troubleshootingâ Grafana doesn't load my pluginâ
Ensure that Grafana has been started in development mode. If you are running Grafana from source, add the following line to your conf/custom.ini
file:
note
If you don't have a conf/custom.ini
file already, create it before proceeding.
You can then start Grafana in development mode by running make run & make run-frontend
in the Grafana repository root.
If you are running Grafana from a binary or inside a Docker container, you can start it in development mode by setting the environment variable GF_DEFAULT_APP_MODE
to development
.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4