chore(http): refactor api handler take advantage of route tree instead of switch statement

is very much WIP at this point
pull/16202/head
Johnny Steenbergen 2019-12-09 15:54:16 -08:00 committed by Johnny Steenbergen
parent b62f29431f
commit 8729cd0959
25 changed files with 261 additions and 374 deletions

View File

@ -2,7 +2,6 @@ package http
import (
"net/http"
"strings"
"github.com/go-chi/chi"
"github.com/influxdata/influxdb"
@ -18,32 +17,7 @@ import (
// APIHandler is a collection of all the service handlers.
type APIHandler struct {
influxdb.HTTPErrorHandler
AssetHandler *AssetHandler
AuthorizationHandler *AuthorizationHandler
BucketHandler *BucketHandler
CheckHandler *CheckHandler
ChronografHandler *ChronografHandler
DashboardHandler *DashboardHandler
DeleteHandler *DeleteHandler
DocumentHandler *DocumentHandler
LabelHandler *LabelHandler
NotificationEndpointHandler *NotificationEndpointHandler
NotificationRuleHandler *NotificationRuleHandler
OrgHandler *OrgHandler
QueryHandler *FluxHandler
ScraperHandler *ScraperHandler
SessionHandler *SessionHandler
SetupHandler *SetupHandler
SourceHandler *SourceHandler
SwaggerHandler http.Handler
TaskHandler *TaskHandler
TelegrafHandler *TelegrafHandler
UserHandler *UserHandler
VariableHandler *VariableHandler
WriteHandler *WriteHandler
Gateway chi.Router
chi.Router
}
// APIBackend is all services and associated parameters required to construct
@ -118,109 +92,117 @@ type ResourceHandler interface {
// APIHandlerOptFn is a functional input param to set parameters on
// the APIHandler.
type APIHandlerOptFn func(*APIHandler)
type APIHandlerOptFn func(chi.Router)
// WithResourceHandler registers a resource handler on the APIHandler.
func WithResourceHandler(resHandler ResourceHandler) APIHandlerOptFn {
return func(h *APIHandler) {
h.Gateway.Mount(resHandler.Prefix(), resHandler)
return func(h chi.Router) {
h.Mount(resHandler.Prefix(), resHandler)
}
}
// NewAPIHandler constructs all api handlers beneath it and returns an APIHandler
func NewAPIHandler(b *APIBackend, opts ...APIHandlerOptFn) *APIHandler {
h := &APIHandler{
HTTPErrorHandler: b.HTTPErrorHandler,
Gateway: newBaseChiRouter(b.HTTPErrorHandler),
}
for _, o := range opts {
o(h)
Router: newBaseChiRouter(b.HTTPErrorHandler),
}
internalURM := b.UserResourceMappingService
b.UserResourceMappingService = authorizer.NewURMService(b.OrgLookupService, b.UserResourceMappingService)
documentBackend := NewDocumentBackend(b.Logger.With(zap.String("handler", "document")), b)
h.DocumentHandler = NewDocumentHandler(documentBackend)
sessionBackend := newSessionBackend(b.Logger.With(zap.String("handler", "session")), b)
h.SessionHandler = NewSessionHandler(b.Logger, sessionBackend)
bucketBackend := NewBucketBackend(b.Logger.With(zap.String("handler", "bucket")), b)
bucketBackend.BucketService = authorizer.NewBucketService(b.BucketService)
h.BucketHandler = NewBucketHandler(b.Logger, bucketBackend)
orgBackend := NewOrgBackend(b.Logger.With(zap.String("handler", "org")), b)
orgBackend.OrganizationService = authorizer.NewOrgService(b.OrganizationService)
h.OrgHandler = NewOrgHandler(b.Logger, orgBackend)
userBackend := NewUserBackend(b.Logger.With(zap.String("handler", "user")), b)
userBackend.UserService = authorizer.NewUserService(b.UserService)
userBackend.PasswordsService = authorizer.NewPasswordService(b.PasswordsService)
h.UserHandler = NewUserHandler(b.Logger, userBackend)
dashboardBackend := NewDashboardBackend(b.Logger.With(zap.String("handler", "dashboard")), b)
dashboardBackend.DashboardService = authorizer.NewDashboardService(b.DashboardService)
h.DashboardHandler = NewDashboardHandler(b.Logger, dashboardBackend)
variableBackend := NewVariableBackend(b.Logger.With(zap.String("handler", "variable")), b)
variableBackend.VariableService = authorizer.NewVariableService(b.VariableService)
h.VariableHandler = NewVariableHandler(b.Logger, variableBackend)
h.Mount("/api/v2", serveLinksHandler(b.HTTPErrorHandler))
authorizationBackend := NewAuthorizationBackend(b.Logger.With(zap.String("handler", "authorization")), b)
authorizationBackend.AuthorizationService = authorizer.NewAuthorizationService(b.AuthorizationService)
h.AuthorizationHandler = NewAuthorizationHandler(b.Logger, authorizationBackend)
h.Mount(prefixAuthorization, NewAuthorizationHandler(b.Logger, authorizationBackend))
bucketBackend := NewBucketBackend(b.Logger.With(zap.String("handler", "bucket")), b)
bucketBackend.BucketService = authorizer.NewBucketService(b.BucketService)
h.Mount(prefixBuckets, NewBucketHandler(b.Logger, bucketBackend))
checkBackend := NewCheckBackend(b.Logger.With(zap.String("handler", "check")), b)
checkBackend.CheckService = authorizer.NewCheckService(b.CheckService,
b.UserResourceMappingService, b.OrganizationService)
h.Mount(prefixChecks, NewCheckHandler(b.Logger, checkBackend))
h.Mount(prefixChronograf, NewChronografHandler(b.ChronografService, b.HTTPErrorHandler))
dashboardBackend := NewDashboardBackend(b.Logger.With(zap.String("handler", "dashboard")), b)
dashboardBackend.DashboardService = authorizer.NewDashboardService(b.DashboardService)
h.Mount(prefixDashboards, NewDashboardHandler(b.Logger, dashboardBackend))
deleteBackend := NewDeleteBackend(b.Logger.With(zap.String("handler", "delete")), b)
h.Mount(prefixDelete, NewDeleteHandler(b.Logger, deleteBackend))
documentBackend := NewDocumentBackend(b.Logger.With(zap.String("handler", "document")), b)
h.Mount(prefixDocuments, NewDocumentHandler(documentBackend))
fluxBackend := NewFluxBackend(b.Logger.With(zap.String("handler", "query")), b)
h.Mount(prefixQuery, NewFluxHandler(b.Logger, fluxBackend))
h.Mount(prefixLabels, NewLabelHandler(b.Logger, authorizer.NewLabelService(b.LabelService), b.HTTPErrorHandler))
notificationEndpointBackend := NewNotificationEndpointBackend(b.Logger.With(zap.String("handler", "notificationEndpoint")), b)
notificationEndpointBackend.NotificationEndpointService = authorizer.NewNotificationEndpointService(b.NotificationEndpointService,
b.UserResourceMappingService, b.OrganizationService)
h.Mount(prefixNotificationEndpoints, NewNotificationEndpointHandler(notificationEndpointBackend.Logger(), notificationEndpointBackend))
notificationRuleBackend := NewNotificationRuleBackend(b.Logger.With(zap.String("handler", "notification_rule")), b)
notificationRuleBackend.NotificationRuleStore = authorizer.NewNotificationRuleStore(b.NotificationRuleStore,
b.UserResourceMappingService, b.OrganizationService)
h.Mount(prefixNotificationRules, NewNotificationRuleHandler(b.Logger, notificationRuleBackend))
orgBackend := NewOrgBackend(b.Logger.With(zap.String("handler", "org")), b)
orgBackend.OrganizationService = authorizer.NewOrgService(b.OrganizationService)
h.Mount(prefixOrganizations, NewOrgHandler(b.Logger, orgBackend))
scraperBackend := NewScraperBackend(b.Logger.With(zap.String("handler", "scraper")), b)
scraperBackend.ScraperStorageService = authorizer.NewScraperTargetStoreService(b.ScraperTargetStoreService,
b.UserResourceMappingService,
b.OrganizationService)
h.ScraperHandler = NewScraperHandler(b.Logger, scraperBackend)
h.Mount(prefixTargets, NewScraperHandler(b.Logger, scraperBackend))
sessionBackend := newSessionBackend(b.Logger.With(zap.String("handler", "session")), b)
sessionHandler := NewSessionHandler(b.Logger, sessionBackend)
h.Mount(prefixSignIn, sessionHandler)
h.Mount(prefixSignOut, sessionHandler)
setupBackend := NewSetupBackend(b.Logger.With(zap.String("handler", "setup")), b)
h.Mount(prefixSetup, NewSetupHandler(b.Logger, setupBackend))
sourceBackend := NewSourceBackend(b.Logger.With(zap.String("handler", "source")), b)
sourceBackend.SourceService = authorizer.NewSourceService(b.SourceService)
sourceBackend.BucketService = authorizer.NewBucketService(b.BucketService)
h.SourceHandler = NewSourceHandler(b.Logger, sourceBackend)
h.Mount(prefixSources, NewSourceHandler(b.Logger, sourceBackend))
setupBackend := NewSetupBackend(b.Logger.With(zap.String("handler", "setup")), b)
h.SetupHandler = NewSetupHandler(b.Logger, setupBackend)
h.Mount("/api/v2/swagger.json", newSwaggerLoader(b.Logger.With(zap.String("service", "swagger-loader")), b.HTTPErrorHandler))
taskBackend := NewTaskBackend(b.Logger.With(zap.String("handler", "task")), b)
h.TaskHandler = NewTaskHandler(b.Logger, taskBackend)
h.TaskHandler.UserResourceMappingService = internalURM
taskHandler := NewTaskHandler(b.Logger, taskBackend)
taskHandler.UserResourceMappingService = internalURM
h.Mount(prefixTasks, taskHandler)
telegrafBackend := NewTelegrafBackend(b.Logger.With(zap.String("handler", "telegraf")), b)
telegrafBackend.TelegrafService = authorizer.NewTelegrafConfigService(b.TelegrafService, b.UserResourceMappingService)
h.TelegrafHandler = NewTelegrafHandler(b.Logger, telegrafBackend)
h.Mount(prefixTelegraf, NewTelegrafHandler(b.Logger, telegrafBackend))
notificationRuleBackend := NewNotificationRuleBackend(b.Logger.With(zap.String("handler", "notification_rule")), b)
notificationRuleBackend.NotificationRuleStore = authorizer.NewNotificationRuleStore(b.NotificationRuleStore,
b.UserResourceMappingService, b.OrganizationService)
h.NotificationRuleHandler = NewNotificationRuleHandler(b.Logger, notificationRuleBackend)
userBackend := NewUserBackend(b.Logger.With(zap.String("handler", "user")), b)
userBackend.UserService = authorizer.NewUserService(b.UserService)
userBackend.PasswordsService = authorizer.NewPasswordService(b.PasswordsService)
userHandler := NewUserHandler(b.Logger, userBackend)
h.Mount(prefixMe, userHandler)
h.Mount(prefixUsers, userHandler)
notificationEndpointBackend := NewNotificationEndpointBackend(b.Logger.With(zap.String("handler", "notificationEndpoint")), b)
notificationEndpointBackend.NotificationEndpointService = authorizer.NewNotificationEndpointService(b.NotificationEndpointService,
b.UserResourceMappingService, b.OrganizationService)
h.NotificationEndpointHandler = NewNotificationEndpointHandler(notificationEndpointBackend.Logger(), notificationEndpointBackend)
checkBackend := NewCheckBackend(b.Logger.With(zap.String("handler", "check")), b)
checkBackend.CheckService = authorizer.NewCheckService(b.CheckService,
b.UserResourceMappingService, b.OrganizationService)
h.CheckHandler = NewCheckHandler(b.Logger, checkBackend)
variableBackend := NewVariableBackend(b.Logger.With(zap.String("handler", "variable")), b)
variableBackend.VariableService = authorizer.NewVariableService(b.VariableService)
h.Mount(prefixVariables, NewVariableHandler(b.Logger, variableBackend))
writeBackend := NewWriteBackend(b.Logger.With(zap.String("handler", "write")), b)
h.WriteHandler = NewWriteHandler(b.Logger, writeBackend)
deleteBackend := NewDeleteBackend(b.Logger.With(zap.String("handler", "delete")), b)
h.DeleteHandler = NewDeleteHandler(b.Logger, deleteBackend)
fluxBackend := NewFluxBackend(b.Logger.With(zap.String("handler", "query")), b)
h.QueryHandler = NewFluxHandler(b.Logger, fluxBackend)
h.ChronografHandler = NewChronografHandler(b.ChronografService, b.HTTPErrorHandler)
h.SwaggerHandler = newSwaggerLoader(b.Logger.With(zap.String("service", "swagger-loader")), b.HTTPErrorHandler)
h.LabelHandler = NewLabelHandler(b.Logger, authorizer.NewLabelService(b.LabelService), b.HTTPErrorHandler)
h.Mount(prefixWrite, NewWriteHandler(b.Logger, writeBackend))
for _, o := range opts {
o(h)
}
return h
}
@ -264,144 +246,12 @@ var apiLinks = map[string]interface{}{
"delete": "/api/v2/delete",
}
func (h *APIHandler) serveLinks(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
if err := encodeResponse(ctx, w, http.StatusOK, apiLinks); err != nil {
h.HandleHTTPError(ctx, err, w)
func serveLinksHandler(errorHandler influxdb.HTTPErrorHandler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
if err := encodeResponse(ctx, w, http.StatusOK, apiLinks); err != nil {
errorHandler.HandleHTTPError(ctx, err, w)
}
}
}
// ServeHTTP delegates a request to the appropriate subhandler.
func (h *APIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
setCORSResponseHeaders(w, r)
if r.Method == "OPTIONS" {
return
}
// Serve the links base links for the API.
if r.URL.Path == "/api/v2/" || r.URL.Path == "/api/v2" {
h.serveLinks(w, r)
return
}
if r.URL.Path == "/api/v2/signin" || r.URL.Path == "/api/v2/signout" {
h.SessionHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/setup") {
h.SetupHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/write") {
h.WriteHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/delete") {
h.DeleteHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/query") {
h.QueryHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/buckets") {
h.BucketHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/labels") {
h.LabelHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/users") {
h.UserHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/me") {
h.UserHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/orgs") {
h.OrgHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/authorizations") {
h.AuthorizationHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/dashboards") {
h.DashboardHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/sources") {
h.SourceHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/scrapers") {
h.ScraperHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/tasks") {
h.TaskHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/checks") {
h.CheckHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/telegrafs") {
h.TelegrafHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/notificationRules") {
h.NotificationRuleHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/notificationEndpoints") {
h.NotificationEndpointHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/variables") {
h.VariableHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/api/v2/documents") {
h.DocumentHandler.ServeHTTP(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/chronograf/") {
h.ChronografHandler.ServeHTTP(w, r)
return
}
if r.URL.Path == "/api/v2/swagger.json" {
h.SwaggerHandler.ServeHTTP(w, r)
return
}
// router has not found route registered on it directly
// if a route slips through, then the same 404 as before
// if a route matches on the gateway router, it will use
// whatever handler that matches the router in question.
h.Gateway.ServeHTTP(w, r)
return http.HandlerFunc(fn)
}

View File

@ -17,6 +17,8 @@ import (
platcontext "github.com/influxdata/influxdb/context"
)
const prefixAuthorization = "/api/v2/authorizations"
// AuthorizationBackend is all services and associated parameters required to construct
// the AuthorizationHandler.
type AuthorizationBackend struct {

View File

@ -60,7 +60,7 @@ type BucketHandler struct {
}
const (
bucketsPath = "/api/v2/buckets"
prefixBuckets = "/api/v2/buckets"
bucketsIDPath = "/api/v2/buckets/:id"
bucketsIDLogPath = "/api/v2/buckets/:id/logs"
bucketsIDMembersPath = "/api/v2/buckets/:id/members"
@ -86,8 +86,8 @@ func NewBucketHandler(log *zap.Logger, b *BucketBackend) *BucketHandler {
OrganizationService: b.OrganizationService,
}
h.HandlerFunc("POST", bucketsPath, h.handlePostBucket)
h.HandlerFunc("GET", bucketsPath, h.handleGetBuckets)
h.HandlerFunc("POST", prefixBuckets, h.handlePostBucket)
h.HandlerFunc("GET", prefixBuckets, h.handleGetBuckets)
h.HandlerFunc("GET", bucketsIDPath, h.handleGetBucket)
h.HandlerFunc("GET", bucketsIDLogPath, h.handleGetBucketLog)
h.HandlerFunc("PATCH", bucketsIDPath, h.handlePatchBucket)
@ -307,7 +307,7 @@ func newBucketsResponse(ctx context.Context, opts influxdb.FindOptions, f influx
rs = append(rs, newBucketResponse(b, labels))
}
return &bucketsResponse{
Links: newPagingLinks(bucketsPath, opts, f, len(bs)),
Links: newPagingLinks(prefixBuckets, opts, f, len(bs)),
Buckets: rs,
}
}
@ -433,7 +433,7 @@ type getBucketRequest struct {
}
func bucketIDPath(id influxdb.ID) string {
return path.Join(bucketsPath, id.String())
return path.Join(prefixBuckets, id.String())
}
// hanldeGetBucketLog retrieves a bucket log by the buckets ID.
@ -824,7 +824,7 @@ func (s *BucketService) FindBuckets(ctx context.Context, filter influxdb.BucketF
var bs bucketsResponse
err := s.Client.
Get(bucketsPath).
Get(prefixBuckets).
QueryParams(params...).
DecodeJSON(&bs).
Do(ctx)
@ -852,7 +852,7 @@ func (s *BucketService) CreateBucket(ctx context.Context, b *influxdb.Bucket) er
var br bucketResponse
err := s.Client.
Post(httpc.BodyJSON(newBucket(b)), bucketsPath).
Post(httpc.BodyJSON(newBucket(b)), prefixBuckets).
DecodeJSON(&br).
Do(ctx)
if err != nil {

View File

@ -58,7 +58,7 @@ type CheckHandler struct {
}
const (
checksPath = "/api/v2/checks"
prefixChecks = "/api/v2/checks"
checksIDPath = "/api/v2/checks/:id"
checksIDQueryPath = "/api/v2/checks/:id/query"
checksIDMembersPath = "/api/v2/checks/:id/members"
@ -83,8 +83,8 @@ func NewCheckHandler(log *zap.Logger, b *CheckBackend) *CheckHandler {
TaskService: b.TaskService,
OrganizationService: b.OrganizationService,
}
h.HandlerFunc("POST", checksPath, h.handlePostCheck)
h.HandlerFunc("GET", checksPath, h.handleGetChecks)
h.HandlerFunc("POST", prefixChecks, h.handlePostCheck)
h.HandlerFunc("GET", prefixChecks, h.handleGetChecks)
h.HandlerFunc("GET", checksIDPath, h.handleGetCheck)
h.HandlerFunc("GET", checksIDQueryPath, h.handleGetCheckQuery)
h.HandlerFunc("DELETE", checksIDPath, h.handleDeleteCheck)
@ -213,7 +213,7 @@ func (h *CheckHandler) newCheckResponse(ctx context.Context, chk influxdb.Check,
func (h *CheckHandler) newChecksResponse(ctx context.Context, chks []influxdb.Check, labelService influxdb.LabelService, f influxdb.PagingFilter, opts influxdb.FindOptions) *checksResponse {
resp := &checksResponse{
Checks: []*checkResponse{},
Links: newPagingLinks(checksPath, opts, f, len(chks)),
Links: newPagingLinks(prefixChecks, opts, f, len(chks)),
}
for _, chk := range chks {
labels, _ := labelService.FindResourceLabels(ctx, influxdb.LabelMappingFilter{ResourceID: chk.GetID()})

View File

@ -6,6 +6,8 @@ import (
"github.com/influxdata/influxdb/chronograf/server"
)
const prefixChronograf = "/chronograf"
// ChronografHandler is an http handler for serving chronograf chronografs.
type ChronografHandler struct {
*httprouter.Router

View File

@ -55,7 +55,7 @@ type DashboardHandler struct {
}
const (
dashboardsPath = "/api/v2/dashboards"
prefixDashboards = "/api/v2/dashboards"
dashboardsIDPath = "/api/v2/dashboards/:id"
dashboardsIDCellsPath = "/api/v2/dashboards/:id/cells"
dashboardsIDCellsIDPath = "/api/v2/dashboards/:id/cells/:cellID"
@ -83,8 +83,8 @@ func NewDashboardHandler(log *zap.Logger, b *DashboardBackend) *DashboardHandler
UserService: b.UserService,
}
h.HandlerFunc("POST", dashboardsPath, h.handlePostDashboard)
h.HandlerFunc("GET", dashboardsPath, h.handleGetDashboards)
h.HandlerFunc("POST", prefixDashboards, h.handlePostDashboard)
h.HandlerFunc("GET", prefixDashboards, h.handleGetDashboards)
h.HandlerFunc("GET", dashboardsIDPath, h.handleGetDashboard)
h.HandlerFunc("GET", dashboardsIDLogPath, h.handleGetDashboardLog)
h.HandlerFunc("DELETE", dashboardsIDPath, h.handleDeleteDashboard)
@ -442,7 +442,7 @@ func (d getDashboardsResponse) toPlatform() []*platform.Dashboard {
func newGetDashboardsResponse(ctx context.Context, dashboards []*platform.Dashboard, filter platform.DashboardFilter, opts platform.FindOptions, labelService platform.LabelService) getDashboardsResponse {
res := getDashboardsResponse{
Links: newPagingLinks(dashboardsPath, opts, filter, len(dashboards)),
Links: newPagingLinks(prefixDashboards, opts, filter, len(dashboards)),
Dashboards: make([]dashboardResponse, 0, len(dashboards)),
}
@ -1088,7 +1088,7 @@ type DashboardService struct {
func (s *DashboardService) FindDashboardByID(ctx context.Context, id platform.ID) (*platform.Dashboard, error) {
var dr dashboardResponse
err := s.Client.
Get(dashboardsPath, id.String()).
Get(prefixDashboards, id.String()).
QueryParams([2]string{"include", "properties"}).
DecodeJSON(&dr).
Do(ctx)
@ -1114,7 +1114,7 @@ func (s *DashboardService) FindDashboards(ctx context.Context, filter platform.D
var dr getDashboardsResponse
err := s.Client.
Get(dashboardsPath).
Get(prefixDashboards).
QueryParams(queryPairs...).
DecodeJSON(&dr).
Do(ctx)
@ -1129,7 +1129,7 @@ func (s *DashboardService) FindDashboards(ctx context.Context, filter platform.D
// CreateDashboard creates a new dashboard and sets b.ID with the new identifier.
func (s *DashboardService) CreateDashboard(ctx context.Context, d *platform.Dashboard) error {
return s.Client.
Post(httpc.BodyJSON(d), dashboardsPath).
Post(httpc.BodyJSON(d), prefixDashboards).
DecodeJSON(d).
Do(ctx)
}
@ -1139,7 +1139,7 @@ func (s *DashboardService) CreateDashboard(ctx context.Context, d *platform.Dash
func (s *DashboardService) UpdateDashboard(ctx context.Context, id platform.ID, upd platform.DashboardUpdate) (*platform.Dashboard, error) {
var d platform.Dashboard
err := s.Client.
Patch(httpc.BodyJSON(upd), dashboardsPath, id.String()).
Patch(httpc.BodyJSON(upd), prefixDashboards, id.String()).
DecodeJSON(&d).
Do(ctx)
if err != nil {
@ -1234,7 +1234,7 @@ func (s *DashboardService) ReplaceDashboardCells(ctx context.Context, id platfor
}
func dashboardIDPath(id platform.ID) string {
return path.Join(dashboardsPath, id.String())
return path.Join(prefixDashboards, id.String())
}
func cellPath(id platform.ID) string {

View File

@ -52,7 +52,7 @@ type DeleteHandler struct {
}
const (
deletePath = "/api/v2/delete"
prefixDelete = "/api/v2/delete"
)
// NewDeleteHandler creates a new handler at /api/v2/delete to recieve delete requests.
@ -67,7 +67,7 @@ func NewDeleteHandler(log *zap.Logger, b *DeleteBackend) *DeleteHandler {
OrganizationService: b.OrganizationService,
}
h.HandlerFunc("POST", deletePath, h.handleDelete)
h.HandlerFunc("POST", prefixDelete, h.handleDelete)
return h
}
@ -225,7 +225,7 @@ type DeleteService struct {
// DeleteBucketRangePredicate send delete request over http to delete points.
func (s *DeleteService) DeleteBucketRangePredicate(ctx context.Context, dr DeleteRequest) error {
u, err := NewURL(s.Addr, deletePath)
u, err := NewURL(s.Addr, prefixDelete)
if err != nil {
return err
}

View File

@ -12,6 +12,8 @@ import (
"go.uber.org/zap"
)
const prefixDocuments = "/api/v2/documents"
// DocumentBackend is all services and associated parameters required to construct
// the DocumentHandler.
type DocumentBackend struct {

View File

@ -24,7 +24,7 @@ type LabelHandler struct {
}
const (
labelsPath = "/api/v2/labels"
prefixLabels = "/api/v2/labels"
labelsIDPath = "/api/v2/labels/:id"
)
@ -37,8 +37,8 @@ func NewLabelHandler(log *zap.Logger, s influxdb.LabelService, he influxdb.HTTPE
LabelService: s,
}
h.HandlerFunc("POST", labelsPath, h.handlePostLabel)
h.HandlerFunc("GET", labelsPath, h.handleGetLabels)
h.HandlerFunc("POST", prefixLabels, h.handlePostLabel)
h.HandlerFunc("GET", prefixLabels, h.handleGetLabels)
h.HandlerFunc("GET", labelsIDPath, h.handleGetLabel)
h.HandlerFunc("PATCH", labelsIDPath, h.handlePatchLabel)
@ -517,7 +517,7 @@ func decodeDeleteLabelMappingRequest(ctx context.Context, r *http.Request) (*del
}
func labelIDPath(id influxdb.ID) string {
return path.Join(labelsPath, id.String())
return path.Join(prefixLabels, id.String())
}
// LabelService connects to Influx via HTTP using tokens to manage labels
@ -551,7 +551,7 @@ func (s *LabelService) FindLabels(ctx context.Context, filter influxdb.LabelFilt
var lr labelsResponse
err := s.Client.
Get(labelsPath).
Get(prefixLabels).
QueryParams(params...).
DecodeJSON(&lr).
Do(ctx)
@ -582,7 +582,7 @@ func (s *LabelService) FindResourceLabels(ctx context.Context, filter influxdb.L
func (s *LabelService) CreateLabel(ctx context.Context, l *influxdb.Label) error {
var lr labelResponse
err := s.Client.
Post(httpc.BodyJSON(l), labelsPath).
Post(httpc.BodyJSON(l), prefixLabels).
DecodeJSON(&lr).
Do(ctx)
if err != nil {

View File

@ -15,6 +15,16 @@ import (
// Middleware constructor.
type Middleware func(http.Handler) http.Handler
func skipOptionsMW(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
if r.Method == "OPTIONS" {
return
}
next.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}
// LoggingMW middleware for logging inflight http requests.
func LoggingMW(log *zap.Logger) Middleware {
return func(next http.Handler) http.Handler {
@ -130,16 +140,16 @@ func ignoreMethod(ignoredMethods ...string) isValidMethodFn {
}
var blacklistEndpoints = map[string]isValidMethodFn{
"/api/v2/signin": ignoreMethod(),
"/api/v2/signout": ignoreMethod(),
mePath: ignoreMethod(),
prefixSignIn: ignoreMethod(),
prefixSignOut: ignoreMethod(),
prefixMe: ignoreMethod(),
mePasswordPath: ignoreMethod(),
usersPasswordPath: ignoreMethod(),
writePath: ignoreMethod("POST"),
prefixWrite: ignoreMethod("POST"),
organizationsIDSecretsPath: ignoreMethod("PATCH"),
organizationsIDSecretsDeletePath: ignoreMethod("POST"),
setupPath: ignoreMethod("POST"),
notificationEndpointsPath: ignoreMethod("POST"),
prefixSetup: ignoreMethod("POST"),
prefixNotificationEndpoints: ignoreMethod("POST"),
notificationEndpointsIDPath: ignoreMethod("PUT"),
}

View File

@ -63,7 +63,7 @@ type NotificationEndpointHandler struct {
}
const (
notificationEndpointsPath = "/api/v2/notificationEndpoints"
prefixNotificationEndpoints = "/api/v2/notificationEndpoints"
notificationEndpointsIDPath = "/api/v2/notificationEndpoints/:id"
notificationEndpointsIDMembersPath = "/api/v2/notificationEndpoints/:id/members"
notificationEndpointsIDMembersIDPath = "/api/v2/notificationEndpoints/:id/members/:userID"
@ -87,8 +87,8 @@ func NewNotificationEndpointHandler(log *zap.Logger, b *NotificationEndpointBack
OrganizationService: b.OrganizationService,
SecretService: b.SecretService,
}
h.HandlerFunc("POST", notificationEndpointsPath, h.handlePostNotificationEndpoint)
h.HandlerFunc("GET", notificationEndpointsPath, h.handleGetNotificationEndpoints)
h.HandlerFunc("POST", prefixNotificationEndpoints, h.handlePostNotificationEndpoint)
h.HandlerFunc("GET", prefixNotificationEndpoints, h.handleGetNotificationEndpoints)
h.HandlerFunc("GET", notificationEndpointsIDPath, h.handleGetNotificationEndpoint)
h.HandlerFunc("DELETE", notificationEndpointsIDPath, h.handleDeleteNotificationEndpoint)
h.HandlerFunc("PUT", notificationEndpointsIDPath, h.handlePutNotificationEndpoint)
@ -196,7 +196,7 @@ func newNotificationEndpointResponse(edp influxdb.NotificationEndpoint, labels [
func newNotificationEndpointsResponse(ctx context.Context, edps []influxdb.NotificationEndpoint, labelService influxdb.LabelService, f influxdb.PagingFilter, opts influxdb.FindOptions) *notificationEndpointsResponse {
resp := &notificationEndpointsResponse{
NotificationEndpoints: make([]notificationEndpointResponse, len(edps)),
Links: newPagingLinks(notificationEndpointsPath, opts, f, len(edps)),
Links: newPagingLinks(prefixNotificationEndpoints, opts, f, len(edps)),
}
for i, edp := range edps {
labels, _ := labelService.FindResourceLabels(ctx, influxdb.LabelMappingFilter{ResourceID: edp.GetID()})
@ -611,7 +611,7 @@ var _ influxdb.NotificationEndpointService = (*NotificationEndpointService)(nil)
func (s *NotificationEndpointService) FindNotificationEndpointByID(ctx context.Context, id influxdb.ID) (influxdb.NotificationEndpoint, error) {
var resp notificationEndpointResponse
err := s.Client.
Get(notificationEndpointsPath, id.String()).
Get(prefixNotificationEndpoints, id.String()).
DecodeJSON(&resp).
Do(ctx)
if err != nil {
@ -636,7 +636,7 @@ func (s *NotificationEndpointService) FindNotificationEndpoints(ctx context.Cont
var resp notificationEndpointsResponse
err := s.Client.
Get(notificationEndpointsPath).
Get(prefixNotificationEndpoints).
QueryParams(params...).
DecodeJSON(&resp).
Do(ctx)
@ -660,7 +660,7 @@ func (s *NotificationEndpointService) CreateNotificationEndpoint(ctx context.Con
// the token/auth. its a nothing burger here
var resp notificationEndpointResponse
err := s.Client.
Post(httpc.BodyJSON(ne), notificationEndpointsPath).
Post(httpc.BodyJSON(ne), prefixNotificationEndpoints).
DecodeJSON(&resp).
Do(ctx)
if err != nil {
@ -677,7 +677,7 @@ func (s *NotificationEndpointService) CreateNotificationEndpoint(ctx context.Con
func (s *NotificationEndpointService) UpdateNotificationEndpoint(ctx context.Context, id influxdb.ID, nr influxdb.NotificationEndpoint, userID influxdb.ID) (influxdb.NotificationEndpoint, error) {
var resp notificationEndpointResponse
err := s.Client.
Put(httpc.BodyJSON(nr), notificationEndpointsPath, id.String()).
Put(httpc.BodyJSON(nr), prefixNotificationEndpoints, id.String()).
DecodeJSON(&resp).
Do(ctx)
if err != nil {
@ -695,7 +695,7 @@ func (s *NotificationEndpointService) PatchNotificationEndpoint(ctx context.Cont
var resp notificationEndpointResponse
err := s.Client.
Patch(httpc.BodyJSON(upd), notificationEndpointsPath, id.String()).
Patch(httpc.BodyJSON(upd), prefixNotificationEndpoints, id.String()).
DecodeJSON(&resp).
Do(ctx)
if err != nil {

View File

@ -65,7 +65,7 @@ type NotificationRuleHandler struct {
}
const (
notificationRulesPath = "/api/v2/notificationRules"
prefixNotificationRules = "/api/v2/notificationRules"
notificationRulesIDPath = "/api/v2/notificationRules/:id"
notificationRulesIDQueryPath = "/api/v2/notificationRules/:id/query"
notificationRulesIDMembersPath = "/api/v2/notificationRules/:id/members"
@ -91,8 +91,8 @@ func NewNotificationRuleHandler(log *zap.Logger, b *NotificationRuleBackend) *No
OrganizationService: b.OrganizationService,
TaskService: b.TaskService,
}
h.HandlerFunc("POST", notificationRulesPath, h.handlePostNotificationRule)
h.HandlerFunc("GET", notificationRulesPath, h.handleGetNotificationRules)
h.HandlerFunc("POST", prefixNotificationRules, h.handlePostNotificationRule)
h.HandlerFunc("GET", prefixNotificationRules, h.handleGetNotificationRules)
h.HandlerFunc("GET", notificationRulesIDPath, h.handleGetNotificationRule)
h.HandlerFunc("GET", notificationRulesIDQueryPath, h.handleGetNotificationRuleQuery)
h.HandlerFunc("DELETE", notificationRulesIDPath, h.handleDeleteNotificationRule)
@ -209,7 +209,7 @@ func (h *NotificationRuleHandler) newNotificationRuleResponse(ctx context.Contex
func (h *NotificationRuleHandler) newNotificationRulesResponse(ctx context.Context, nrs []influxdb.NotificationRule, labelService influxdb.LabelService, f influxdb.PagingFilter, opts influxdb.FindOptions) (*notificationRulesResponse, error) {
resp := &notificationRulesResponse{
NotificationRules: []*notificationRuleResponse{},
Links: newPagingLinks(notificationRulesPath, opts, f, len(nrs)),
Links: newPagingLinks(prefixNotificationRules, opts, f, len(nrs)),
}
for _, nr := range nrs {
labels, _ := labelService.FindResourceLabels(ctx, influxdb.LabelMappingFilter{ResourceID: nr.GetID()})

View File

@ -39,7 +39,7 @@ type SetupHandler struct {
}
const (
setupPath = "/api/v2/setup"
prefixSetup = "/api/v2/setup"
)
// NewSetupHandler returns a new instance of SetupHandler.
@ -50,8 +50,8 @@ func NewSetupHandler(log *zap.Logger, b *SetupBackend) *SetupHandler {
log: log,
OnboardingService: b.OnboardingService,
}
h.HandlerFunc("POST", setupPath, h.handlePostSetup)
h.HandlerFunc("GET", setupPath, h.isOnboarding)
h.HandlerFunc("POST", prefixSetup, h.handlePostSetup)
h.HandlerFunc("GET", prefixSetup, h.isOnboarding)
return h
}
@ -141,7 +141,7 @@ type SetupService struct {
// IsOnboarding determine if onboarding request is allowed.
func (s *SetupService) IsOnboarding(ctx context.Context) (bool, error) {
u, err := NewURL(s.Addr, setupPath)
u, err := NewURL(s.Addr, prefixSetup)
if err != nil {
return false, err
}
@ -168,7 +168,7 @@ func (s *SetupService) IsOnboarding(ctx context.Context) (bool, error) {
// Generate OnboardingResults.
func (s *SetupService) Generate(ctx context.Context, or *platform.OnboardingRequest) (*platform.OnboardingResults, error) {
u, err := NewURL(s.Addr, setupPath)
u, err := NewURL(s.Addr, prefixSetup)
if err != nil {
return nil, err
}

View File

@ -58,7 +58,7 @@ type OrgHandler struct {
}
const (
organizationsPath = "/api/v2/orgs"
prefixOrganizations = "/api/v2/orgs"
organizationsIDPath = "/api/v2/orgs/:id"
organizationsIDLogPath = "/api/v2/orgs/:id/logs"
organizationsIDMembersPath = "/api/v2/orgs/:id/members"
@ -109,8 +109,8 @@ func NewOrgHandler(log *zap.Logger, b *OrgBackend) *OrgHandler {
UserService: b.UserService,
}
h.HandlerFunc("POST", organizationsPath, h.handlePostOrg)
h.HandlerFunc("GET", organizationsPath, h.handleGetOrgs)
h.HandlerFunc("POST", prefixOrganizations, h.handlePostOrg)
h.HandlerFunc("GET", prefixOrganizations, h.handleGetOrgs)
h.HandlerFunc("GET", organizationsIDPath, h.handleGetOrg)
h.HandlerFunc("GET", organizationsIDLogPath, h.handleGetOrgLog)
h.HandlerFunc("PATCH", organizationsIDPath, h.handlePatchOrg)

View File

@ -14,12 +14,17 @@ type PlatformHandler struct {
APIHandler http.Handler
}
func setCORSResponseHeaders(w http.ResponseWriter, r *http.Request) {
if origin := r.Header.Get("Origin"); origin != "" {
w.Header().Set("Access-Control-Allow-Origin", origin)
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, Authorization")
func setCORSResponseHeaders(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
if origin := r.Header.Get("Origin"); origin != "" {
w.Header().Set("Access-Control-Allow-Origin", origin)
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, Authorization")
}
next.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}
// NewPlatformHandler returns a platform handler that serves the API and associated assets.
@ -41,20 +46,18 @@ func NewPlatformHandler(b *APIBackend, opts ...APIHandlerOptFn) *PlatformHandler
assetHandler := NewAssetHandler()
assetHandler.Path = b.AssetsPath
wrappedHandler := setCORSResponseHeaders(h)
wrappedHandler = skipOptionsMW(wrappedHandler)
return &PlatformHandler{
AssetHandler: assetHandler,
DocsHandler: Redoc("/api/v2/swagger.json"),
APIHandler: h,
APIHandler: wrappedHandler,
}
}
// ServeHTTP delegates a request to the appropriate subhandler.
func (h *PlatformHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
setCORSResponseHeaders(w, r)
if r.Method == "OPTIONS" {
return
}
if strings.HasPrefix(r.URL.Path, "/docs") {
h.DocsHandler.ServeHTTP(w, r)
return

View File

@ -25,7 +25,6 @@ import (
"github.com/influxdata/influxdb/kit/check"
"github.com/influxdata/influxdb/kit/tracing"
"github.com/influxdata/influxdb/logger"
influxlogger "github.com/influxdata/influxdb/logger"
"github.com/influxdata/influxdb/query"
"github.com/pkg/errors"
prom "github.com/prometheus/client_golang/prometheus"
@ -33,7 +32,7 @@ import (
)
const (
fluxPath = "/api/v2/query"
prefixQuery = "/api/v2/query"
traceIDHeader = "Trace-Id"
)
@ -78,6 +77,11 @@ type FluxHandler struct {
EventRecorder metric.EventRecorder
}
// Prefix provides the route prefix.
func (*FluxHandler) Prefix() string {
return prefixQuery
}
// NewFluxHandler returns a new handler at /api/v2/query for flux queries.
func NewFluxHandler(log *zap.Logger, b *FluxBackend) *FluxHandler {
h := &FluxHandler{
@ -93,7 +97,7 @@ func NewFluxHandler(log *zap.Logger, b *FluxBackend) *FluxHandler {
// query reponses can optionally be gzip encoded
qh := gziphandler.GzipHandler(http.HandlerFunc(h.handleQuery))
h.Handler("POST", fluxPath, qh)
h.Handler("POST", prefixQuery, qh)
h.HandlerFunc("POST", "/api/v2/query/ast", h.postFluxAST)
h.HandlerFunc("POST", "/api/v2/query/analyze", h.postQueryAnalyze)
h.HandlerFunc("GET", "/api/v2/query/suggestions", h.getFluxSuggestions)
@ -107,7 +111,7 @@ func (h *FluxHandler) handleQuery(w http.ResponseWriter, r *http.Request) {
defer span.Finish()
ctx := r.Context()
log := h.log.With(influxlogger.TraceFields(ctx)...)
log := h.log.With(logger.TraceFields(ctx)...)
if id, _, found := logger.TraceInfo(ctx); found {
w.Header().Set(traceIDHeader, id)
}
@ -353,7 +357,7 @@ type FluxService struct {
func (s *FluxService) Query(ctx context.Context, w io.Writer, r *query.ProxyRequest) (flux.Statistics, error) {
span, ctx := tracing.StartSpanFromContext(ctx)
defer span.Finish()
u, err := NewURL(s.Addr, fluxPath)
u, err := NewURL(s.Addr, prefixQuery)
if err != nil {
return flux.Statistics{}, tracing.LogError(span, err)
}
@ -416,7 +420,7 @@ func (s *FluxQueryService) Query(ctx context.Context, r *query.Request) (flux.Re
span, ctx := tracing.StartSpanFromContext(ctx)
defer span.Finish()
u, err := NewURL(s.Addr, fluxPath)
u, err := NewURL(s.Addr, prefixQuery)
if err != nil {
return nil, tracing.LogError(span, err)
}
@ -474,7 +478,7 @@ func (s FluxQueryService) Check(ctx context.Context) check.Response {
// SimpleQuery runs a flux query with common parameters and returns CSV results.
func SimpleQuery(addr, flux, org, token string) ([]byte, error) {
u, err := NewURL(addr, fluxPath)
u, err := NewURL(addr, prefixQuery)
if err != nil {
return nil, err
}

View File

@ -8,6 +8,7 @@ import (
"sync"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/influxdata/httprouter"
platform "github.com/influxdata/influxdb"
influxlogger "github.com/influxdata/influxdb/logger"
@ -31,6 +32,9 @@ func newBaseChiRouter(errorHandler platform.HTTPErrorHandler) chi.Router {
bh := baseHandler{HTTPErrorHandler: errorHandler}
router.NotFound(bh.notFound)
router.MethodNotAllowed(bh.methodNotAllowed)
router.Use(skipOptionsMW)
router.Use(middleware.StripSlashes)
router.Use(setCORSResponseHeaders)
return router
}

View File

@ -57,13 +57,13 @@ type ScraperHandler struct {
}
const (
targetsPath = "/api/v2/scrapers"
targetsIDMembersPath = targetsPath + "/:id/members"
targetsIDMembersIDPath = targetsPath + "/:id/members/:userID"
targetsIDOwnersPath = targetsPath + "/:id/owners"
targetsIDOwnersIDPath = targetsPath + "/:id/owners/:userID"
targetsIDLabelsPath = targetsPath + "/:id/labels"
targetsIDLabelsIDPath = targetsPath + "/:id/labels/:lid"
prefixTargets = "/api/v2/scrapers"
targetsIDMembersPath = prefixTargets + "/:id/members"
targetsIDMembersIDPath = prefixTargets + "/:id/members/:userID"
targetsIDOwnersPath = prefixTargets + "/:id/owners"
targetsIDOwnersIDPath = prefixTargets + "/:id/owners/:userID"
targetsIDLabelsPath = prefixTargets + "/:id/labels"
targetsIDLabelsIDPath = prefixTargets + "/:id/labels/:lid"
)
// NewScraperHandler returns a new instance of ScraperHandler.
@ -79,11 +79,11 @@ func NewScraperHandler(log *zap.Logger, b *ScraperBackend) *ScraperHandler {
BucketService: b.BucketService,
OrganizationService: b.OrganizationService,
}
h.HandlerFunc("POST", targetsPath, h.handlePostScraperTarget)
h.HandlerFunc("GET", targetsPath, h.handleGetScraperTargets)
h.HandlerFunc("GET", targetsPath+"/:id", h.handleGetScraperTarget)
h.HandlerFunc("PATCH", targetsPath+"/:id", h.handlePatchScraperTarget)
h.HandlerFunc("DELETE", targetsPath+"/:id", h.handleDeleteScraperTarget)
h.HandlerFunc("POST", prefixTargets, h.handlePostScraperTarget)
h.HandlerFunc("GET", prefixTargets, h.handleGetScraperTargets)
h.HandlerFunc("GET", prefixTargets+"/:id", h.handleGetScraperTarget)
h.HandlerFunc("PATCH", prefixTargets+"/:id", h.handlePatchScraperTarget)
h.HandlerFunc("DELETE", prefixTargets+"/:id", h.handleDeleteScraperTarget)
memberBackend := MemberBackend{
HTTPErrorHandler: b.HTTPErrorHandler,
@ -344,7 +344,7 @@ type ScraperService struct {
// ListTargets returns a list of all scraper targets.
func (s *ScraperService) ListTargets(ctx context.Context, filter influxdb.ScraperTargetFilter) ([]influxdb.ScraperTarget, error) {
url, err := NewURL(s.Addr, targetsPath)
url, err := NewURL(s.Addr, prefixTargets)
if err != nil {
return nil, err
}
@ -443,7 +443,7 @@ func (s *ScraperService) UpdateTarget(ctx context.Context, update *influxdb.Scra
// AddTarget creates a new scraper target and sets target.ID with the new identifier.
func (s *ScraperService) AddTarget(ctx context.Context, target *influxdb.ScraperTarget, userID influxdb.ID) error {
url, err := NewURL(s.Addr, targetsPath)
url, err := NewURL(s.Addr, prefixTargets)
if err != nil {
return err
}
@ -553,7 +553,7 @@ func (s *ScraperService) GetTargetByID(ctx context.Context, id influxdb.ID) (*in
}
func targetIDPath(id influxdb.ID) string {
return path.Join(targetsPath, id.String())
return path.Join(prefixTargets, id.String())
}
type getTargetsLinks struct {
@ -583,7 +583,7 @@ type targetResponse struct {
func (h *ScraperHandler) newListTargetsResponse(ctx context.Context, targets []influxdb.ScraperTarget) (getTargetsResponse, error) {
res := getTargetsResponse{
Links: getTargetsLinks{
Self: targetsPath,
Self: prefixTargets,
},
Targets: make([]targetResponse, 0, len(targets)),
}

View File

@ -9,6 +9,11 @@ import (
"go.uber.org/zap"
)
const (
prefixSignIn = "/api/v2/signin"
prefixSignOut = "/api/v2/signout"
)
// SessionBackend is all services and associated parameters required to construct
// the SessionHandler.
type SessionBackend struct {
@ -55,8 +60,8 @@ func NewSessionHandler(log *zap.Logger, b *SessionBackend) *SessionHandler {
UserService: b.UserService,
}
h.HandlerFunc("POST", "/api/v2/signin", h.handleSignin)
h.HandlerFunc("POST", "/api/v2/signout", h.handleSignout)
h.HandlerFunc("POST", prefixSignIn, h.handleSignin)
h.HandlerFunc("POST", prefixSignOut, h.handleSignout)
return h
}

View File

@ -20,7 +20,7 @@ import (
)
const (
sourceHTTPPath = "/api/v2/sources"
prefixSources = "/api/v2/sources"
)
type sourceResponse struct {
@ -36,10 +36,10 @@ func newSourceResponse(s *platform.Source) *sourceResponse {
return &sourceResponse{
Source: s,
Links: map[string]interface{}{
"self": fmt.Sprintf("%s/%s", sourceHTTPPath, s.ID.String()),
"query": fmt.Sprintf("%s/%s/query", sourceHTTPPath, s.ID.String()),
"buckets": fmt.Sprintf("%s/%s/buckets", sourceHTTPPath, s.ID.String()),
"health": fmt.Sprintf("%s/%s/health", sourceHTTPPath, s.ID.String()),
"self": fmt.Sprintf("%s/%s", prefixSources, s.ID.String()),
"query": fmt.Sprintf("%s/%s/query", prefixSources, s.ID.String()),
"buckets": fmt.Sprintf("%s/%s/buckets", prefixSources, s.ID.String()),
"health": fmt.Sprintf("%s/%s/health", prefixSources, s.ID.String()),
},
}
}
@ -47,10 +47,10 @@ func newSourceResponse(s *platform.Source) *sourceResponse {
return &sourceResponse{
Source: s,
Links: map[string]interface{}{
"self": fmt.Sprintf("%s/%s", sourceHTTPPath, s.ID.String()),
"query": fmt.Sprintf("%s/%s/query", sourceHTTPPath, s.ID.String()),
"buckets": fmt.Sprintf("%s/%s/buckets", sourceHTTPPath, s.ID.String()),
"health": fmt.Sprintf("%s/%s/health", sourceHTTPPath, s.ID.String()),
"self": fmt.Sprintf("%s/%s", prefixSources, s.ID.String()),
"query": fmt.Sprintf("%s/%s/query", prefixSources, s.ID.String()),
"buckets": fmt.Sprintf("%s/%s/buckets", prefixSources, s.ID.String()),
"health": fmt.Sprintf("%s/%s/health", prefixSources, s.ID.String()),
},
}
}
@ -63,7 +63,7 @@ type sourcesResponse struct {
func newSourcesResponse(srcs []*platform.Source) *sourcesResponse {
res := &sourcesResponse{
Links: map[string]interface{}{
"self": sourceHTTPPath,
"self": prefixSources,
},
}
@ -127,7 +127,7 @@ func NewSourceHandler(log *zap.Logger, b *SourceBackend) *SourceHandler {
NewQueryService: b.NewQueryService,
}
h.HandlerFunc("POST", "/api/v2/sources", h.handlePostSource)
h.HandlerFunc("POST", prefixSources, h.handlePostSource)
h.HandlerFunc("GET", "/api/v2/sources", h.handleGetSources)
h.HandlerFunc("GET", "/api/v2/sources/:id", h.handleGetSource)
h.HandlerFunc("PATCH", "/api/v2/sources/:id", h.handlePatchSource)

View File

@ -68,7 +68,7 @@ type TaskHandler struct {
}
const (
tasksPath = "/api/v2/tasks"
prefixTasks = "/api/v2/tasks"
tasksIDPath = "/api/v2/tasks/:id"
tasksIDLogsPath = "/api/v2/tasks/:id/logs"
tasksIDMembersPath = "/api/v2/tasks/:id/members"
@ -99,8 +99,8 @@ func NewTaskHandler(log *zap.Logger, b *TaskBackend) *TaskHandler {
BucketService: b.BucketService,
}
h.HandlerFunc("GET", tasksPath, h.handleGetTasks)
h.HandlerFunc("POST", tasksPath, h.handlePostTask)
h.HandlerFunc("GET", prefixTasks, h.handleGetTasks)
h.HandlerFunc("POST", prefixTasks, h.handlePostTask)
h.HandlerFunc("GET", tasksIDPath, h.handleGetTask)
h.HandlerFunc("PATCH", tasksIDPath, h.handleUpdateTask)
@ -314,7 +314,7 @@ type tasksResponse struct {
func newTasksResponse(ctx context.Context, ts []*influxdb.Task, f influxdb.TaskFilter, labelService influxdb.LabelService) tasksResponse {
rs := tasksResponse{
Links: newTasksPagingLinks(tasksPath, ts, f),
Links: newTasksPagingLinks(prefixTasks, ts, f),
Tasks: make([]taskResponse, len(ts)),
}
@ -1458,7 +1458,7 @@ func (t TaskService) FindTasks(ctx context.Context, filter influxdb.TaskFilter)
span, _ := tracing.StartSpanFromContext(ctx)
defer span.Finish()
u, err := NewURL(t.Addr, tasksPath)
u, err := NewURL(t.Addr, prefixTasks)
if err != nil {
return nil, 0, err
}
@ -1524,7 +1524,7 @@ func (t TaskService) CreateTask(ctx context.Context, tc influxdb.TaskCreate) (*T
span, _ := tracing.StartSpanFromContext(ctx)
defer span.Finish()
u, err := NewURL(t.Addr, tasksPath)
u, err := NewURL(t.Addr, prefixTasks)
if err != nil {
return nil, err
}
@ -1913,13 +1913,13 @@ func (t TaskService) CancelRun(ctx context.Context, taskID, runID influxdb.ID) e
}
func taskIDPath(id influxdb.ID) string {
return path.Join(tasksPath, id.String())
return path.Join(prefixTasks, id.String())
}
func taskIDRunsPath(id influxdb.ID) string {
return path.Join(tasksPath, id.String(), "runs")
return path.Join(prefixTasks, id.String(), "runs")
}
func taskIDRunIDPath(taskID, runID influxdb.ID) string {
return path.Join(tasksPath, taskID.String(), "runs", runID.String())
return path.Join(prefixTasks, taskID.String(), "runs", runID.String())
}

View File

@ -57,7 +57,7 @@ type TelegrafHandler struct {
}
const (
telegrafsPath = "/api/v2/telegrafs"
prefixTelegraf = "/api/v2/telegrafs"
telegrafsIDPath = "/api/v2/telegrafs/:id"
telegrafsIDMembersPath = "/api/v2/telegrafs/:id/members"
telegrafsIDMembersIDPath = "/api/v2/telegrafs/:id/members/:userID"
@ -80,8 +80,8 @@ func NewTelegrafHandler(log *zap.Logger, b *TelegrafBackend) *TelegrafHandler {
UserService: b.UserService,
OrganizationService: b.OrganizationService,
}
h.HandlerFunc("POST", telegrafsPath, h.handlePostTelegraf)
h.HandlerFunc("GET", telegrafsPath, h.handleGetTelegrafs)
h.HandlerFunc("POST", prefixTelegraf, h.handlePostTelegraf)
h.HandlerFunc("GET", prefixTelegraf, h.handleGetTelegrafs)
h.HandlerFunc("GET", telegrafsIDPath, h.handleGetTelegraf)
h.HandlerFunc("DELETE", telegrafsIDPath, h.handleDeleteTelegraf)
h.HandlerFunc("PUT", telegrafsIDPath, h.handlePutTelegraf)
@ -448,7 +448,7 @@ var _ platform.TelegrafConfigStore = (*TelegrafService)(nil)
func (s *TelegrafService) FindTelegrafConfigByID(ctx context.Context, id platform.ID) (*platform.TelegrafConfig, error) {
var cfg platform.TelegrafConfig
err := s.client.
Get(telegrafsPath, id.String()).
Get(prefixTelegraf, id.String()).
Header("Accept", "application/json").
DecodeJSON(&cfg).
Do(ctx)
@ -479,7 +479,7 @@ func (s *TelegrafService) FindTelegrafConfigs(ctx context.Context, f platform.Te
Configs []*platform.TelegrafConfig `json:"configurations"`
}
err := s.client.
Get(telegrafsPath).
Get(prefixTelegraf).
QueryParams(params...).
DecodeJSON(&resp).
Do(ctx)
@ -494,7 +494,7 @@ func (s *TelegrafService) FindTelegrafConfigs(ctx context.Context, f platform.Te
func (s *TelegrafService) CreateTelegrafConfig(ctx context.Context, tc *platform.TelegrafConfig, userID platform.ID) error {
var teleResp platform.TelegrafConfig
err := s.client.
Post(httpc.BodyJSON(tc), telegrafsPath).
Post(httpc.BodyJSON(tc), prefixTelegraf).
DecodeJSON(&teleResp).
Do(ctx)
if err != nil {
@ -513,6 +513,6 @@ func (s *TelegrafService) UpdateTelegrafConfig(ctx context.Context, id platform.
// DeleteTelegrafConfig removes a telegraf config by ID.
func (s *TelegrafService) DeleteTelegrafConfig(ctx context.Context, id platform.ID) error {
return s.client.
Delete(telegrafsPath, id.String()).
Delete(prefixTelegraf, id.String()).
Do(ctx)
}

View File

@ -46,8 +46,8 @@ type UserHandler struct {
}
const (
usersPath = "/api/v2/users"
mePath = "/api/v2/me"
prefixUsers = "/api/v2/users"
prefixMe = "/api/v2/me"
mePasswordPath = "/api/v2/me/password"
usersIDPath = "/api/v2/users/:id"
usersPasswordPath = "/api/v2/users/:id/password"
@ -66,8 +66,8 @@ func NewUserHandler(log *zap.Logger, b *UserBackend) *UserHandler {
PasswordsService: b.PasswordsService,
}
h.HandlerFunc("POST", usersPath, h.handlePostUser)
h.HandlerFunc("GET", usersPath, h.handleGetUsers)
h.HandlerFunc("POST", prefixUsers, h.handlePostUser)
h.HandlerFunc("GET", prefixUsers, h.handleGetUsers)
h.HandlerFunc("GET", usersIDPath, h.handleGetUser)
h.HandlerFunc("GET", usersLogPath, h.handleGetUserLog)
h.HandlerFunc("PATCH", usersIDPath, h.handlePatchUser)
@ -78,7 +78,7 @@ func NewUserHandler(log *zap.Logger, b *UserBackend) *UserHandler {
h.HandlerFunc("POST", usersPasswordPath, h.handlePostUserPassword)
h.HandlerFunc("PUT", usersPasswordPath, h.handlePutUserPassword)
h.HandlerFunc("GET", mePath, h.handleGetMe)
h.HandlerFunc("GET", prefixMe, h.handleGetMe)
h.HandlerFunc("PUT", mePasswordPath, h.handlePutUserPassword)
return h
@ -493,7 +493,7 @@ type UserService struct {
// FindMe returns user information about the owner of the token
func (s *UserService) FindMe(ctx context.Context, id influxdb.ID) (*influxdb.User, error) {
url, err := NewURL(s.Addr, mePath)
url, err := NewURL(s.Addr, prefixMe)
if err != nil {
return nil, err
}
@ -584,7 +584,7 @@ func (s *UserService) FindUser(ctx context.Context, filter influxdb.UserFilter)
// FindUsers returns a list of users that match filter and the total count of matching users.
// Additional options provide pagination & sorting.
func (s *UserService) FindUsers(ctx context.Context, filter influxdb.UserFilter, opt ...influxdb.FindOptions) ([]*influxdb.User, int, error) {
url, err := NewURL(s.Addr, usersPath)
url, err := NewURL(s.Addr, prefixUsers)
if err != nil {
return nil, 0, err
}
@ -627,7 +627,7 @@ func (s *UserService) FindUsers(ctx context.Context, filter influxdb.UserFilter,
// CreateUser creates a new user and sets u.ID with the new identifier.
func (s *UserService) CreateUser(ctx context.Context, u *influxdb.User) error {
url, err := NewURL(s.Addr, usersPath)
url, err := NewURL(s.Addr, prefixUsers)
if err != nil {
return err
}
@ -730,7 +730,7 @@ func (s *UserService) DeleteUser(ctx context.Context, id influxdb.ID) error {
}
func userIDPath(id influxdb.ID) string {
return path.Join(usersPath, id.String())
return path.Join(prefixUsers, id.String())
}
// hanldeGetUserLog retrieves a user log by the users ID.

View File

@ -13,7 +13,7 @@ import (
)
const (
variablePath = "/api/v2/variables"
prefixVariables = "/api/v2/variables"
)
// VariableBackend is all services and associated parameters required to construct
@ -57,12 +57,12 @@ func NewVariableHandler(log *zap.Logger, b *VariableBackend) *VariableHandler {
LabelService: b.LabelService,
}
entityPath := fmt.Sprintf("%s/:id", variablePath)
entityPath := fmt.Sprintf("%s/:id", prefixVariables)
entityLabelsPath := fmt.Sprintf("%s/labels", entityPath)
entityLabelsIDPath := fmt.Sprintf("%s/:lid", entityLabelsPath)
h.HandlerFunc("GET", variablePath, h.handleGetVariables)
h.HandlerFunc("POST", variablePath, h.handlePostVariable)
h.HandlerFunc("GET", prefixVariables, h.handleGetVariables)
h.HandlerFunc("POST", prefixVariables, h.handlePostVariable)
h.HandlerFunc("GET", entityPath, h.handleGetVariable)
h.HandlerFunc("PATCH", entityPath, h.handlePatchVariable)
h.HandlerFunc("PUT", entityPath, h.handlePutVariable)
@ -98,7 +98,7 @@ func newGetVariablesResponse(ctx context.Context, variables []*platform.Variable
num := len(variables)
resp := getVariablesResponse{
Variables: make([]variableResponse, 0, num),
Links: newPagingLinks(variablePath, opts, f, num),
Links: newPagingLinks(prefixVariables, opts, f, num),
}
for _, variable := range variables {
@ -444,7 +444,7 @@ type VariableService struct {
func (s *VariableService) FindVariableByID(ctx context.Context, id platform.ID) (*platform.Variable, error) {
var mr variableResponse
err := s.Client.
Get(variablePath, id.String()).
Get(prefixVariables, id.String()).
DecodeJSON(&mr).
Do(ctx)
if err != nil {
@ -470,7 +470,7 @@ func (s *VariableService) FindVariables(ctx context.Context, filter platform.Var
var ms getVariablesResponse
err := s.Client.
Get(variablePath).
Get(prefixVariables).
QueryParams(params...).
DecodeJSON(&ms).
Do(ctx)
@ -491,7 +491,7 @@ func (s *VariableService) CreateVariable(ctx context.Context, m *platform.Variab
}
return s.Client.
Post(httpc.BodyJSON(m), variablePath).
Post(httpc.BodyJSON(m), prefixVariables).
DecodeJSON(m).
Do(ctx)
}
@ -500,7 +500,7 @@ func (s *VariableService) CreateVariable(ctx context.Context, m *platform.Variab
func (s *VariableService) UpdateVariable(ctx context.Context, id platform.ID, update *platform.VariableUpdate) (*platform.Variable, error) {
var m platform.Variable
err := s.Client.
Patch(httpc.BodyJSON(update), variablePath, id.String()).
Patch(httpc.BodyJSON(update), prefixVariables, id.String()).
DecodeJSON(&m).
Do(ctx)
if err != nil {
@ -513,7 +513,7 @@ func (s *VariableService) UpdateVariable(ctx context.Context, id platform.ID, up
// ReplaceVariable replaces a single variable
func (s *VariableService) ReplaceVariable(ctx context.Context, variable *platform.Variable) error {
return s.Client.
Put(httpc.BodyJSON(variable), variablePath, variable.ID.String()).
Put(httpc.BodyJSON(variable), prefixVariables, variable.ID.String()).
DecodeJSON(variable).
Do(ctx)
}
@ -521,6 +521,6 @@ func (s *VariableService) ReplaceVariable(ctx context.Context, variable *platfor
// DeleteVariable removes a variable from the store
func (s *VariableService) DeleteVariable(ctx context.Context, id platform.ID) error {
return s.Client.
Delete(variablePath, id.String()).
Delete(prefixVariables, id.String()).
Do(ctx)
}

View File

@ -60,8 +60,13 @@ type WriteHandler struct {
EventRecorder metric.EventRecorder
}
// Prefix provides the route prefix.
func (*WriteHandler) Prefix() string {
return prefixWrite
}
const (
writePath = "/api/v2/write"
prefixWrite = "/api/v2/write"
errInvalidGzipHeader = "gzipped HTTP body contains an invalid header"
errInvalidPrecision = "invalid precision; valid precision units are ns, us, ms, and s"
)
@ -79,7 +84,7 @@ func NewWriteHandler(log *zap.Logger, b *WriteBackend) *WriteHandler {
EventRecorder: b.WriteEventRecorder,
}
h.HandlerFunc("POST", writePath, h.handleWrite)
h.HandlerFunc("POST", prefixWrite, h.handleWrite)
return h
}
@ -305,7 +310,7 @@ func (s *WriteService) Write(ctx context.Context, orgID, bucketID influxdb.ID, r
}
}
u, err := NewURL(s.Addr, writePath)
u, err := NewURL(s.Addr, prefixWrite)
if err != nil {
return err
}