为应用插件添加资源处理器
您可以向应用后端添加资源处理器,以使用您自己的应用特定路由扩展 Grafana HTTP API。本指南解释了您可能需要添加资源处理器的理由以及一些常见的操作方法。
资源处理器的用途
应用通常与某种 HTTP 服务(例如第三方服务)集成以检索和发送数据。例如,此服务可能具有特定的身份验证和授权需求,或者具有不适合返回到 Grafana 和插件前端的响应格式。
此外,您可能希望保护您的资源,以便只有具有特定权限的用户才能访问某些路由。
资源处理器也可用于构建允许用户写回应用的控制面板。例如,您可以添加一个资源处理器来更新物联网设备的状态。
实现资源处理器接口
要向后端插件添加资源处理器,您需要实现backend.CallResourceHandler
接口。
您可以在插件中通过两种方式实现此功能,使用httpadapter
包或手动实现它。
使用httpadapter
包
由Grafana 插件 Go SDK提供的httpadapter
包是处理资源的推荐方法。此包提供对使用http.Handler
接口处理资源调用的支持,并允许以更 Go 独立的方式响应 HTTP 请求,并使支持多个路由和方法(GET、POST 等)变得更容易。
使用http.Handler
还可以使用 Go 的内置路由功能,称为ServeMux
或您首选的 HTTP 路由库(例如gorilla/mux
)。
在以下示例中,我们演示了如何使用httpadapter
包、ServeMux
和http.Handler
来添加对检索命名空间(/namespaces
)、项目(/projects
)和更新某些设备状态(/device
)的支持。
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)
}
访问后端插件上下文
您可以使用backend.PluginConfigFromContext函数来访问backend.PluginContext。它包含有关插件请求的上下文信息,例如执行请求的用户。
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)
}
手动实现backend.CallResourceHandler
对于基本需求,手动实现backend.CallResourceHandler
接口可能就足够了。要支持几个不同的检索数据的路由,您可以使用带有req.Path
的 switch 语句。
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,
})
}
}
访问应用资源
实现后,您可以使用 Grafana HTTP API 和前端访问这些资源。
使用 Grafana HTTP API
您可以通过使用端点http://<GRAFANA_HOSTNAME>:<PORT>/api/plugins/<PLUGIN_ID>/resources{/<RESOURCE>}
来通过 Grafana HTTP API 访问资源。PLUGIN_ID
是唯一标识应用的插件标识符,RESOURCE
取决于资源处理器的实现方式以及支持哪些资源(路由)。
使用上述示例,您可以访问以下资源:
- HTTP GET
http://<GRAFANA_HOSTNAME>:<PORT>/api/plugins/<PLUGIN_ID>/resources/namespaces
- HTTP GET
http://<GRAFANA_HOSTNAME>:<PORT>/api/plugins/<PLUGIN_ID>/resources/projects
从前端
您可以在组件中使用backendSrv
运行时服务的get
函数向http://<GRAFANA_HOSTNAME>:<PORT>/api/plugins/<PLUGIN_ID>/resources/namespaces
发送 HTTP GET 请求来访问您的资源。
import { getBackendSrv } from '@grafana/runtime';
const namespaces = await getBackendSrv().get(`/api/plugins/<PLUGIN_ID>/resources/namespaces`);
其他示例
使用资源处理器和httpadapter
包的一些其他示例:
- 带有后端的应用示例
- 在后端创建资源处理器和注册路由。
- 使用backendSrv调用资源。