diff --git a/http/query.go b/http/query.go index 6b3b848101..f3940874eb 100644 --- a/http/query.go +++ b/http/query.go @@ -337,8 +337,18 @@ func QueryRequestFromProxyRequest(req *query.ProxyRequest) (*QueryRequest, error func decodeQueryRequest(ctx context.Context, r *http.Request, svc platform.OrganizationService) (*QueryRequest, error) { var req QueryRequest - if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - return nil, err + // TODO(desa): I'm not sure I like this kind of conditional logic, but it feels better than + // introducing another method that does this exact thing. + if r.Method == http.MethodGet { + qp := r.URL.Query() + req.Query = qp.Get("query") + if req.Query == "" { + return nil, errors.New("query param \"query\" is required") + } + } else { + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + return nil, err + } } req = req.WithDefaults() diff --git a/http/query_handler.go b/http/query_handler.go index e5979fd213..47208348b0 100644 --- a/http/query_handler.go +++ b/http/query_handler.go @@ -47,7 +47,8 @@ func NewFluxHandler() *FluxHandler { Logger: zap.NewNop(), } - h.HandlerFunc("POST", fluxPath, h.handlePostQuery) + h.HandlerFunc("POST", fluxPath, h.handleQuery) + h.HandlerFunc("GET", fluxPath, h.handleQuery) h.HandlerFunc("POST", "/api/v2/query/ast", h.postFluxAST) h.HandlerFunc("POST", "/api/v2/query/analyze", h.postQueryAnalyze) h.HandlerFunc("POST", "/api/v2/query/spec", h.postFluxSpec) @@ -56,7 +57,7 @@ func NewFluxHandler() *FluxHandler { return h } -func (h *FluxHandler) handlePostQuery(w http.ResponseWriter, r *http.Request) { +func (h *FluxHandler) handleQuery(w http.ResponseWriter, r *http.Request) { ctx := r.Context() a, err := pcontext.GetAuthorizer(ctx) diff --git a/http/query_test.go b/http/query_test.go index 4bc8be848c..fb46b0ffba 100644 --- a/http/query_test.go +++ b/http/query_test.go @@ -436,7 +436,7 @@ func Test_decodeProxyQueryRequest(t *testing.T) { wantErr bool }{ { - name: "valid query request", + name: "valid post query request", args: args{ r: httptest.NewRequest("POST", "/", bytes.NewBufferString(`{"query": "from()"}`)), svc: &mock.OrganizationService{ @@ -462,6 +462,33 @@ func Test_decodeProxyQueryRequest(t *testing.T) { }, }, }, + { + name: "valid get query request", + args: args{ + r: httptest.NewRequest("GET", "/api/v2/query?query=from(bucket%3A%20%22mybucket%22)&org=myorg", nil), + svc: &mock.OrganizationService{ + FindOrganizationF: func(ctx context.Context, filter platform.OrganizationFilter) (*platform.Organization, error) { + return &platform.Organization{ + ID: func() platform.ID { s, _ := platform.IDFromString("deadbeefdeadbeef"); return *s }(), + }, nil + }, + }, + }, + want: &query.ProxyRequest{ + Request: query.Request{ + OrganizationID: func() platform.ID { s, _ := platform.IDFromString("deadbeefdeadbeef"); return *s }(), + Compiler: lang.FluxCompiler{ + Query: "from(bucket: \"mybucket\")", + }, + }, + Dialect: &csv.Dialect{ + ResultEncoderConfig: csv.ResultEncoderConfig{ + NoHeader: false, + Delimiter: ',', + }, + }, + }, + }, } var cmpOptions = cmp.Options{ cmpopts.IgnoreUnexported(query.ProxyRequest{}),