From 8729cd095975ca55dcd38dc7c5720eba7f622ea8 Mon Sep 17 00:00:00 2001 From: Johnny Steenbergen Date: Mon, 9 Dec 2019 15:54:16 -0800 Subject: [PATCH] chore(http): refactor api handler take advantage of route tree instead of switch statement is very much WIP at this point --- http/api_handler.go | 314 +++++++++------------------------- http/auth_service.go | 2 + http/bucket_service.go | 14 +- http/check_service.go | 8 +- http/chronograf_handler.go | 2 + http/dashboard_service.go | 18 +- http/delete_handler.go | 6 +- http/document_service.go | 2 + http/label_service.go | 12 +- http/middleware.go | 22 ++- http/notification_endpoint.go | 18 +- http/notification_rule.go | 8 +- http/onboarding.go | 10 +- http/org_service.go | 6 +- http/platform_handler.go | 25 +-- http/query_handler.go | 18 +- http/router.go | 4 + http/scraper_service.go | 32 ++-- http/session_handler.go | 9 +- http/source_service.go | 22 +-- http/task_service.go | 18 +- http/telegraf.go | 14 +- http/user_service.go | 18 +- http/variable_service.go | 22 +-- http/write_handler.go | 11 +- 25 files changed, 261 insertions(+), 374 deletions(-) diff --git a/http/api_handler.go b/http/api_handler.go index 3d58421391..7eb9bed323 100644 --- a/http/api_handler.go +++ b/http/api_handler.go @@ -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) } diff --git a/http/auth_service.go b/http/auth_service.go index ea746d6031..acdd85663a 100644 --- a/http/auth_service.go +++ b/http/auth_service.go @@ -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 { diff --git a/http/bucket_service.go b/http/bucket_service.go index 2389ac2e52..3557cb4893 100644 --- a/http/bucket_service.go +++ b/http/bucket_service.go @@ -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 { diff --git a/http/check_service.go b/http/check_service.go index 76a216c860..1b82e62e12 100644 --- a/http/check_service.go +++ b/http/check_service.go @@ -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()}) diff --git a/http/chronograf_handler.go b/http/chronograf_handler.go index d59dfb003c..39a9ab9ef8 100644 --- a/http/chronograf_handler.go +++ b/http/chronograf_handler.go @@ -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 diff --git a/http/dashboard_service.go b/http/dashboard_service.go index 4cb7b97bac..4cdb59cc5c 100644 --- a/http/dashboard_service.go +++ b/http/dashboard_service.go @@ -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 { diff --git a/http/delete_handler.go b/http/delete_handler.go index 0c2091ed18..1b3d85519f 100644 --- a/http/delete_handler.go +++ b/http/delete_handler.go @@ -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 } diff --git a/http/document_service.go b/http/document_service.go index 163a4470c5..a7858c48f7 100644 --- a/http/document_service.go +++ b/http/document_service.go @@ -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 { diff --git a/http/label_service.go b/http/label_service.go index 584216c030..4008bf8d77 100644 --- a/http/label_service.go +++ b/http/label_service.go @@ -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 { diff --git a/http/middleware.go b/http/middleware.go index 61e957175b..5a5bd50811 100644 --- a/http/middleware.go +++ b/http/middleware.go @@ -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"), } diff --git a/http/notification_endpoint.go b/http/notification_endpoint.go index e320d8208e..77fbf3b84a 100644 --- a/http/notification_endpoint.go +++ b/http/notification_endpoint.go @@ -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 := ¬ificationEndpointsResponse{ 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 { diff --git a/http/notification_rule.go b/http/notification_rule.go index 50b472d976..532025b255 100644 --- a/http/notification_rule.go +++ b/http/notification_rule.go @@ -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 := ¬ificationRulesResponse{ 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()}) diff --git a/http/onboarding.go b/http/onboarding.go index 7215f54ebf..c2a7a7bfd0 100644 --- a/http/onboarding.go +++ b/http/onboarding.go @@ -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 } diff --git a/http/org_service.go b/http/org_service.go index 22cf4dfbfe..dd958db2ad 100644 --- a/http/org_service.go +++ b/http/org_service.go @@ -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) diff --git a/http/platform_handler.go b/http/platform_handler.go index 988c079344..3d2c0167b4 100644 --- a/http/platform_handler.go +++ b/http/platform_handler.go @@ -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 diff --git a/http/query_handler.go b/http/query_handler.go index 318e15154f..6536620222 100644 --- a/http/query_handler.go +++ b/http/query_handler.go @@ -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 } diff --git a/http/router.go b/http/router.go index b771f27fa2..f17ca8ee36 100644 --- a/http/router.go +++ b/http/router.go @@ -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 } diff --git a/http/scraper_service.go b/http/scraper_service.go index 78b3759ed5..cbfbda364c 100644 --- a/http/scraper_service.go +++ b/http/scraper_service.go @@ -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)), } diff --git a/http/session_handler.go b/http/session_handler.go index bce1752fd1..3f6a35b54f 100644 --- a/http/session_handler.go +++ b/http/session_handler.go @@ -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 } diff --git a/http/source_service.go b/http/source_service.go index 719bca8668..3a83551924 100644 --- a/http/source_service.go +++ b/http/source_service.go @@ -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) diff --git a/http/task_service.go b/http/task_service.go index 52a7057dc2..a4d5592864 100644 --- a/http/task_service.go +++ b/http/task_service.go @@ -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()) } diff --git a/http/telegraf.go b/http/telegraf.go index e143f2e466..2790a22a42 100644 --- a/http/telegraf.go +++ b/http/telegraf.go @@ -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) } diff --git a/http/user_service.go b/http/user_service.go index d2f6254ca2..17d0c0e966 100644 --- a/http/user_service.go +++ b/http/user_service.go @@ -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. diff --git a/http/variable_service.go b/http/variable_service.go index 3c41d8ada8..7374f9546a 100644 --- a/http/variable_service.go +++ b/http/variable_service.go @@ -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) } diff --git a/http/write_handler.go b/http/write_handler.go index d23bb09a8e..8229d5e708 100644 --- a/http/write_handler.go +++ b/http/write_handler.go @@ -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 }