influxdb/http/proto.go

173 lines
3.9 KiB
Go

package http
import (
"context"
"encoding/json"
"fmt"
"net/http"
platform "github.com/influxdata/influxdb"
"github.com/julienschmidt/httprouter"
"go.uber.org/zap"
)
// ProtoHandler is the handler for creating instances of
// prebuilt resources (dashboards, tasks, etcd).
type ProtoHandler struct {
*httprouter.Router
Logger *zap.Logger
ProtoService platform.ProtoService
LabelService platform.LabelService
}
const (
protosPath = "/api/v2/protos"
protosDashboardsPath = "/api/v2/protos/:protoID/dashboards"
)
func extractID(ctx context.Context, s string) (platform.ID, error) {
params := httprouter.ParamsFromContext(ctx)
idStr := params.ByName(s)
if idStr == "" {
return 0, platform.NewError(platform.WithErrorMsg("url missing protoID"), platform.WithErrorCode(platform.EInvalid))
}
var id platform.ID
if err := id.DecodeFromString(idStr); err != nil {
return 0, err
}
return id, nil
}
func extractProtoID(ctx context.Context) (platform.ID, error) {
return extractID(ctx, "protoID")
}
// ProtoBackend is the backend for the proto handler.
type ProtoBackend struct {
Logger *zap.Logger
ProtoService platform.ProtoService
LabelService platform.LabelService
}
// NewProtoBackend creates an instance of the Protobackend from the APIBackend.
func NewProtoBackend(b *APIBackend) *ProtoBackend {
return &ProtoBackend{
Logger: b.Logger.With(zap.String("handler", "proto")),
ProtoService: b.ProtoService,
LabelService: b.LabelService,
}
}
// NewProtoHandler creates an instance of a proto handler.
func NewProtoHandler(b *ProtoBackend) *ProtoHandler {
h := &ProtoHandler{
Router: NewRouter(),
Logger: b.Logger,
ProtoService: b.ProtoService,
LabelService: b.LabelService,
}
h.HandlerFunc("GET", protosPath, h.handleGetProtos)
h.HandlerFunc("POST", protosDashboardsPath, h.handlePostProtosDashboards)
return h
}
type protosResponse struct {
Protos []*protoResponse `json:"protos"`
}
func newProtosResponse(ps []*platform.Proto) *protosResponse {
rs := []*protoResponse{}
for _, p := range ps {
rs = append(rs, newProtoResponse(p))
}
return &protosResponse{
Protos: rs,
}
}
type protoResponse struct {
Links map[string]string `json:"links"`
*platform.Proto
}
func newProtoResponse(p *platform.Proto) *protoResponse {
return &protoResponse{
Links: map[string]string{
"dashboards": fmt.Sprintf("/api/v2/protos/%s/dashboards", p.ID),
},
Proto: p,
}
}
func (h *ProtoHandler) handleGetProtos(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
ps, err := h.ProtoService.FindProtos(ctx)
if err != nil {
EncodeError(ctx, err, w)
return
}
if err := encodeResponse(ctx, w, http.StatusOK, newProtosResponse(ps)); err != nil {
logEncodingError(h.Logger, r, err)
return
}
}
type createProtoResourcesRequest struct {
ProtoID platform.ID `json:"-"`
OrganizationID platform.ID `json:"orgID"`
opts platform.FindOptions
}
// Decode turns an http request into a createProtoResourceRequest.
func (r *createProtoResourcesRequest) Decode(req *http.Request) error {
ctx := req.Context()
id, err := extractProtoID(ctx)
if err != nil {
return err
}
opts, err := decodeFindOptions(ctx, req)
if err != nil {
return err
}
r.opts = *opts
r.ProtoID = id
if err := json.NewDecoder(req.Body).Decode(r); err != nil {
return err
}
return nil
}
func (h *ProtoHandler) handlePostProtosDashboards(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req := &createProtoResourcesRequest{}
if err := req.Decode(r); err != nil {
EncodeError(ctx, err, w)
return
}
ds, err := h.ProtoService.CreateDashboardsFromProto(ctx, req.ProtoID, req.OrganizationID)
if err != nil {
EncodeError(ctx, err, w)
return
}
filter := platform.DashboardFilter{OrganizationID: &req.OrganizationID}
if err := encodeResponse(ctx, w, http.StatusCreated, newGetDashboardsResponse(ctx, ds, filter, req.opts, h.LabelService)); err != nil {
logEncodingError(h.Logger, r, err)
return
}
}