From 1f5094d97e5cb588fe89d09b654d19a3aaca2dc8 Mon Sep 17 00:00:00 2001 From: Tomas Touceda Date: Wed, 25 Aug 2021 10:08:14 -0300 Subject: [PATCH] Make adding routes a bit simpler (#1771) * Make adding routes a bit simpler * Remove unused handle * Lint * More lint --- server/service/endpoint_utils.go | 57 +++++++++++++++++++++++++------ server/service/global_policies.go | 34 ------------------ server/service/handler.go | 30 +++++++--------- server/service/team_schedule.go | 34 ------------------ server/service/teams.go | 10 ------ server/service/translator.go | 10 ------ server/service/user_roles.go | 10 ------ 7 files changed, 58 insertions(+), 127 deletions(-) diff --git a/server/service/endpoint_utils.go b/server/service/endpoint_utils.go index 2c4246c4e5..1a98c4f710 100644 --- a/server/service/endpoint_utils.go +++ b/server/service/endpoint_utils.go @@ -11,8 +11,8 @@ import ( "strings" "github.com/fleetdm/fleet/v4/server/fleet" - "github.com/go-kit/kit/endpoint" kithttp "github.com/go-kit/kit/transport/http" + "github.com/gorilla/mux" "github.com/pkg/errors" ) @@ -70,6 +70,11 @@ func allFields(ifv reflect.Value) []reflect.StructField { // IDs are expected to be uint, and can be optional by setting the tag as follows: `url:"some-id,optional"` // list-options are optional by default and it'll ignore the optional portion of the tag. func makeDecoder(iface interface{}) kithttp.DecodeRequestFunc { + if iface == nil { + return func(ctx context.Context, r *http.Request) (interface{}, error) { + return nil, nil + } + } t := reflect.TypeOf(iface) if t.Kind() != reflect.Struct { panic(fmt.Sprintf("makeDecoder only understands structs, not %T", iface)) @@ -132,18 +137,48 @@ func makeDecoder(iface interface{}) kithttp.DecodeRequestFunc { } } -func makeNopDecoder() kithttp.DecodeRequestFunc { - return func(ctx context.Context, r *http.Request) (interface{}, error) { - return nil, nil - } +type UserAuthEndpointer struct { + svc fleet.Service + opts []kithttp.ServerOption + r *mux.Router } -func makeAuthenticatedServiceEndpoint(svc fleet.Service, f handlerFunc) endpoint.Endpoint { - return authenticatedUser(svc, makeServiceEndpoint(svc, f)) +func NewUserAuthenticatedEndpointer(svc fleet.Service, opts []kithttp.ServerOption, r *mux.Router) *UserAuthEndpointer { + return &UserAuthEndpointer{svc: svc, opts: opts, r: r} } -func makeServiceEndpoint(svc fleet.Service, f handlerFunc) endpoint.Endpoint { - return func(ctx context.Context, request interface{}) (interface{}, error) { - return f(ctx, request, svc) - } +func getNameFromPathAndVerb(verb, path string) string { + return strings.ToLower(verb) + "_" + strings.ReplaceAll(strings.TrimSuffix("/api/v1/fleet/", strings.TrimRight(path, "/")), "/", "_") +} + +func (e *UserAuthEndpointer) POST(path string, f handlerFunc, v interface{}) { + e.handle(path, f, v, "POST") +} + +func (e *UserAuthEndpointer) GET(path string, f handlerFunc, v interface{}) { + e.handle(path, f, v, "GET") +} + +func (e *UserAuthEndpointer) PATCH(path string, f handlerFunc, v interface{}) { + e.handle(path, f, v, "PATCH") +} + +func (e *UserAuthEndpointer) DELETE(path string, f handlerFunc, v interface{}) { + e.handle(path, f, v, "DELETE") +} + +func (e *UserAuthEndpointer) handle(path string, f handlerFunc, v interface{}, verb string) *mux.Route { + return e.r.Handle(path, e.makeEndpoint(f, v)).Methods(verb).Name(getNameFromPathAndVerb(verb, path)) +} + +func (e *UserAuthEndpointer) makeEndpoint(f handlerFunc, v interface{}) http.Handler { + return newServer( + authenticatedUser( + e.svc, + func(ctx context.Context, request interface{}) (interface{}, error) { + return f(ctx, request, e.svc) + }), + makeDecoder(v), + e.opts, + ) } diff --git a/server/service/global_policies.go b/server/service/global_policies.go index 63a46f8035..11fe98ee16 100644 --- a/server/service/global_policies.go +++ b/server/service/global_policies.go @@ -2,10 +2,8 @@ package service import ( "context" - "net/http" "github.com/fleetdm/fleet/v4/server/fleet" - kithttp "github.com/go-kit/kit/transport/http" ) ///////////////////////////////////////////////////////////////////////////////// @@ -23,14 +21,6 @@ type globalPolicyResponse struct { func (r globalPolicyResponse) error() error { return r.Err } -func makeGlobalPolicyEndpoint(svc fleet.Service, opts []kithttp.ServerOption) http.Handler { - return newServer( - makeAuthenticatedServiceEndpoint(svc, globalPolicyEndpoint), - makeDecoder(globalPolicyRequest{}), - opts, - ) -} - func globalPolicyEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) { req := request.(*globalPolicyRequest) resp, err := svc.NewGlobalPolicy(ctx, req.QueryID) @@ -59,14 +49,6 @@ type listGlobalPoliciesResponse struct { func (r listGlobalPoliciesResponse) error() error { return r.Err } -func makeListGlobalPoliciesEndpoint(svc fleet.Service, opts []kithttp.ServerOption) http.Handler { - return newServer( - makeAuthenticatedServiceEndpoint(svc, listGlobalPoliciesEndpoint), - makeNopDecoder(), - opts, - ) -} - func listGlobalPoliciesEndpoint(ctx context.Context, _ interface{}, svc fleet.Service) (interface{}, error) { resp, err := svc.ListGlobalPolicies(ctx) if err != nil { @@ -98,14 +80,6 @@ type getPolicyByIDResponse struct { func (r getPolicyByIDResponse) error() error { return r.Err } -func makeGetPolicyByIDEndpoint(svc fleet.Service, opts []kithttp.ServerOption) http.Handler { - return newServer( - makeAuthenticatedServiceEndpoint(svc, getPolicyByIDEndpoint), - makeDecoder(getPolicyByIDRequest{}), - opts, - ) -} - func getPolicyByIDEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) { req := request.(*getPolicyByIDRequest) policy, err := svc.GetPolicyByIDQueries(ctx, req.PolicyID) @@ -143,14 +117,6 @@ type deleteGlobalPoliciesResponse struct { func (r deleteGlobalPoliciesResponse) error() error { return r.Err } -func makeDeleteGlobalPoliciesEndpoint(svc fleet.Service, opts []kithttp.ServerOption) http.Handler { - return newServer( - makeAuthenticatedServiceEndpoint(svc, deleteGlobalPoliciesEndpoint), - makeDecoder(deleteGlobalPoliciesRequest{}), - opts, - ) -} - func deleteGlobalPoliciesEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) { req := request.(*deleteGlobalPoliciesRequest) resp, err := svc.DeleteGlobalPolicies(ctx, req.IDs) diff --git a/server/service/handler.go b/server/service/handler.go index c02779256a..ccd0ff321a 100644 --- a/server/service/handler.go +++ b/server/service/handler.go @@ -676,26 +676,20 @@ func attachFleetAPIRoutes(r *mux.Router, h *fleetHandlers) { } func attachNewStyleFleetAPIRoutes(r *mux.Router, svc fleet.Service, opts []kithttp.ServerOption) { - handle("POST", "/api/v1/fleet/users/roles/spec", makeApplyUserRoleSpecsEndpoint(svc, opts), "apply_user_roles_spec", r) - handle("POST", "/api/v1/fleet/translate", makeTranslatorEndpoint(svc, opts), "translator", r) - handle("POST", "/api/v1/fleet/spec/teams", makeApplyTeamSpecsEndpoint(svc, opts), "apply_team_specs", r) + e := NewUserAuthenticatedEndpointer(svc, opts, r) + e.POST("/api/v1/fleet/users/roles/spec", applyUserRoleSpecsEndpoint, applyUserRoleSpecsRequest{}) + e.POST("/api/v1/fleet/translate", translatorEndpoint, translatorRequest{}) + e.POST("/api/v1/fleet/spec/teams", applyTeamSpecsEndpoint, applyTeamSpecsRequest{}) - handle("GET", "/api/v1/fleet/team/{team_id}/schedule", makeGetTeamScheduleEndpoint(svc, opts), "get_team_schedule", r) - handle("POST", "/api/v1/fleet/team/{team_id}/schedule", makeTeamScheduleQueryEndpoint(svc, opts), "add_to_team_schedule", r) - handle("PATCH", "/api/v1/fleet/team/{team_id}/schedule/{scheduled_query_id}", makeModifyTeamScheduleEndpoint(svc, opts), "edit_team_schedule", r) - handle("DELETE", "/api/v1/fleet/team/{team_id}/schedule/{scheduled_query_id}", makeDeleteTeamScheduleEndpoint(svc, opts), "delete_team_schedule", r) + e.GET("/api/v1/fleet/team/{team_id}/schedule", getTeamScheduleEndpoint, getTeamScheduleRequest{}) + e.POST("/api/v1/fleet/team/{team_id}/schedule", teamScheduleQueryEndpoint, teamScheduleQueryRequest{}) + e.PATCH("/api/v1/fleet/team/{team_id}/schedule/{scheduled_query_id}", modifyTeamScheduleEndpoint, modifyTeamScheduleRequest{}) + e.DELETE("/api/v1/fleet/team/{team_id}/schedule/{scheduled_query_id}", deleteTeamScheduleEndpoint, deleteTeamScheduleRequest{}) - handle("POST", "/api/v1/fleet/global/policies", makeGlobalPolicyEndpoint(svc, opts), "add_to_global_policy", r) - handle("GET", "/api/v1/fleet/global/policies", makeListGlobalPoliciesEndpoint(svc, opts), "list_global_policies", r) - handle("GET", "/api/v1/fleet/global/policies/{policy_id}", makeGetPolicyByIDEndpoint(svc, opts), "get_global_policy_by_id", r) - handle("POST", "/api/v1/fleet/global/policies/delete", makeDeleteGlobalPoliciesEndpoint(svc, opts), "delete_global_policies", r) -} - -func handle(verb, path string, handler http.Handler, name string, r *mux.Router) { - r.Handle( - path, - handler, - ).Methods(verb).Name(name) + e.POST("/api/v1/fleet/global/policies", globalPolicyEndpoint, globalPolicyRequest{}) + e.GET("/api/v1/fleet/global/policies", listGlobalPoliciesEndpoint, nil) + e.GET("/api/v1/fleet/global/policies/{policy_id}", getPolicyByIDEndpoint, getPolicyByIDRequest{}) + e.POST("/api/v1/fleet/global/policies/delete", deleteGlobalPoliciesEndpoint, deleteGlobalPoliciesRequest{}) } // TODO: this duplicates the one in makeKitHandler diff --git a/server/service/team_schedule.go b/server/service/team_schedule.go index 098345ad94..261ec0a98d 100644 --- a/server/service/team_schedule.go +++ b/server/service/team_schedule.go @@ -2,11 +2,9 @@ package service import ( "context" - "net/http" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/ptr" - kithttp "github.com/go-kit/kit/transport/http" "gopkg.in/guregu/null.v3" ) @@ -22,14 +20,6 @@ type getTeamScheduleResponse struct { func (r getTeamScheduleResponse) error() error { return r.Err } -func makeGetTeamScheduleEndpoint(svc fleet.Service, opts []kithttp.ServerOption) http.Handler { - return newServer( - makeAuthenticatedServiceEndpoint(svc, getTeamScheduleEndpoint), - makeDecoder(getTeamScheduleRequest{}), - opts, - ) -} - func getTeamScheduleEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) { req := request.(*getTeamScheduleRequest) resp := getTeamScheduleResponse{Scheduled: []scheduledQueryResponse{}} @@ -74,14 +64,6 @@ type teamScheduleQueryResponse struct { func (r teamScheduleQueryResponse) error() error { return r.Err } -func makeTeamScheduleQueryEndpoint(svc fleet.Service, opts []kithttp.ServerOption) http.Handler { - return newServer( - makeAuthenticatedServiceEndpoint(svc, teamScheduleQueryEndpoint), - makeDecoder(teamScheduleQueryRequest{}), - opts, - ) -} - func uintValueOrZero(v *uint) uint { if v == nil { return 0 @@ -147,14 +129,6 @@ type modifyTeamScheduleResponse struct { func (r modifyTeamScheduleResponse) error() error { return r.Err } -func makeModifyTeamScheduleEndpoint(svc fleet.Service, opts []kithttp.ServerOption) http.Handler { - return newServer( - makeAuthenticatedServiceEndpoint(svc, modifyTeamScheduleEndpoint), - makeDecoder(modifyTeamScheduleRequest{}), - opts, - ) -} - func modifyTeamScheduleEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) { req := request.(*modifyTeamScheduleRequest) resp, err := svc.ModifyTeamScheduledQueries(ctx, req.TeamID, req.ScheduledQueryID, req.ScheduledQueryPayload) @@ -196,14 +170,6 @@ type deleteTeamScheduleResponse struct { func (r deleteTeamScheduleResponse) error() error { return r.Err } -func makeDeleteTeamScheduleEndpoint(svc fleet.Service, opts []kithttp.ServerOption) http.Handler { - return newServer( - makeAuthenticatedServiceEndpoint(svc, deleteTeamScheduleEndpoint), - makeDecoder(deleteTeamScheduleRequest{}), - opts, - ) -} - func deleteTeamScheduleEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) { req := request.(*deleteTeamScheduleRequest) err := svc.DeleteTeamScheduledQueries(ctx, req.TeamID, req.ScheduledQueryID) diff --git a/server/service/teams.go b/server/service/teams.go index 7384323577..d88f023dad 100644 --- a/server/service/teams.go +++ b/server/service/teams.go @@ -3,11 +3,9 @@ package service import ( "context" "database/sql" - "net/http" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/ptr" - kithttp "github.com/go-kit/kit/transport/http" "github.com/pkg/errors" ) @@ -21,14 +19,6 @@ type applyTeamSpecsResponse struct { func (r applyTeamSpecsResponse) error() error { return r.Err } -func makeApplyTeamSpecsEndpoint(svc fleet.Service, opts []kithttp.ServerOption) http.Handler { - return newServer( - makeAuthenticatedServiceEndpoint(svc, applyTeamSpecsEndpoint), - makeDecoder(applyTeamSpecsRequest{}), - opts, - ) -} - func applyTeamSpecsEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) { req := request.(*applyTeamSpecsRequest) err := svc.ApplyTeamSpecs(ctx, req.Specs) diff --git a/server/service/translator.go b/server/service/translator.go index 0b0531335f..18c2203e4c 100644 --- a/server/service/translator.go +++ b/server/service/translator.go @@ -2,10 +2,8 @@ package service import ( "context" - "net/http" "github.com/fleetdm/fleet/v4/server/fleet" - kithttp "github.com/go-kit/kit/transport/http" ) type translatorRequest struct { @@ -19,14 +17,6 @@ type translatorResponse struct { func (r translatorResponse) error() error { return r.Err } -func makeTranslatorEndpoint(svc fleet.Service, opts []kithttp.ServerOption) http.Handler { - return newServer( - makeAuthenticatedServiceEndpoint(svc, translatorEndpoint), - makeDecoder(translatorRequest{}), - opts, - ) -} - func translatorEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) { req := request.(*translatorRequest) resp, err := svc.Translate(ctx, req.List) diff --git a/server/service/user_roles.go b/server/service/user_roles.go index 8872a77c06..d6a189931c 100644 --- a/server/service/user_roles.go +++ b/server/service/user_roles.go @@ -2,10 +2,8 @@ package service import ( "context" - "net/http" "github.com/fleetdm/fleet/v4/server/fleet" - kithttp "github.com/go-kit/kit/transport/http" "gopkg.in/guregu/null.v3" ) @@ -19,14 +17,6 @@ type applyUserRoleSpecsResponse struct { func (r applyUserRoleSpecsResponse) error() error { return r.Err } -func makeApplyUserRoleSpecsEndpoint(svc fleet.Service, opts []kithttp.ServerOption) http.Handler { - return newServer( - makeAuthenticatedServiceEndpoint(svc, applyUserRoleSpecsEndpoint), - makeDecoder(applyUserRoleSpecsRequest{}), - opts, - ) -} - func applyUserRoleSpecsEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) { req := request.(*applyUserRoleSpecsRequest) err := svc.ApplyUserRolesSpecs(ctx, *req.Spec)