diff --git a/go/datas/remote_database_handlers.go b/go/datas/remote_database_handlers.go index a1aef4048c..c58a0adad3 100644 --- a/go/datas/remote_database_handlers.go +++ b/go/datas/remote_database_handlers.go @@ -6,6 +6,7 @@ package datas import ( "compress/gzip" + "errors" "fmt" "io" "io/ioutil" @@ -431,21 +432,32 @@ func handleGraphQL(w http.ResponseWriter, req *http.Request, ps URLParams, cs ch db := NewDatabase(cs) var rootValue types.Value + var err error if len(dsTokens) == 1 { ds := dsTokens[0] dataset := db.GetDataset(ds) - rootValue = dataset.Head() + var ok bool + rootValue, ok = dataset.MaybeHead() + if !ok { + err = fmt.Errorf("Dataset %s not found", ds) + } } else { h := hash.Parse(hTokens[0]) rootValue = db.ReadValue(h) + if rootValue == nil { + err = errors.New("Root value not found") + } } - d.PanicIfTrue(rootValue == nil) w.Header().Add("Content-Type", "application/json") writer := respWriter(req, w) defer writer.Close() - ngql.Query(rootValue, qTokens[0], db, writer) + if err != nil { + ngql.Error(err, writer) + } else { + ngql.Query(rootValue, qTokens[0], db, writer) + } } func handleBaseGet(w http.ResponseWriter, req *http.Request, ps URLParams, rt chunks.ChunkStore) { diff --git a/go/ngql/query.go b/go/ngql/query.go index 1ebbfdf504..583ea5211a 100644 --- a/go/ngql/query.go +++ b/go/ngql/query.go @@ -5,7 +5,6 @@ package ngql import ( - "bytes" "context" "encoding/json" "io" @@ -13,6 +12,7 @@ import ( "github.com/attic-labs/noms/go/d" "github.com/attic-labs/noms/go/types" "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" ) const ( @@ -49,7 +49,7 @@ func constructQueryType(rootValue types.Value, tm *typeMap) *graphql.Object { // Query takes |rootValue|, builds a GraphQL scheme from rootValue.Type() and // executes |query| against it, encoding the result to |w|. -func Query(rootValue types.Value, query string, vr types.ValueReader, w io.Writer) error { +func Query(rootValue types.Value, query string, vr types.ValueReader, w io.Writer) { tm := newTypeMap() queryObj := constructQueryType(rootValue, tm) @@ -63,8 +63,18 @@ func Query(rootValue types.Value, query string, vr types.ValueReader, w io.Write Context: ctx, }) - rJSON, err := json.Marshal(r) - d.Chk.NoError(err) - io.Copy(w, bytes.NewBuffer([]byte(rJSON))) - return nil + err := json.NewEncoder(w).Encode(r) + d.PanicIfError(err) +} + +// Error writes an error as a GraphQL error to a writer. +func Error(err error, w io.Writer) { + r := graphql.Result{ + Errors: []gqlerrors.FormattedError{ + {Message: err.Error()}, + }, + } + + jsonErr := json.NewEncoder(w).Encode(r) + d.PanicIfError(jsonErr) } diff --git a/go/ngql/query_test.go b/go/ngql/query_test.go index c99b560d76..deebdad33d 100644 --- a/go/ngql/query_test.go +++ b/go/ngql/query_test.go @@ -6,6 +6,7 @@ package ngql import ( "bytes" + "errors" "fmt" "testing" @@ -31,7 +32,7 @@ func (suite *QueryGraphQLSuite) SetupTest() { func (suite *QueryGraphQLSuite) assertQueryResult(v types.Value, q, expect string) { buff := &bytes.Buffer{} Query(v, q, suite.vs, buff) - suite.Equal(expect, string(buff.Bytes())) + suite.Equal(expect+"\n", string(buff.Bytes())) } func (suite *QueryGraphQLSuite) TestScalars() { @@ -327,3 +328,10 @@ func (suite *QueryGraphQLSuite) TestLoFi() { t := types.StringType suite.assertQueryResult(t, "{root}", `{"data":{"root":"pej65tf21rubhu9cb0oi5gqrkgf26aql"}}`) } + +func (suite *QueryGraphQLSuite) TestError() { + buff := &bytes.Buffer{} + Error(errors.New("Some error string"), buff) + suite.Equal(buff.String(), `{"data":null,"errors":[{"message":"Some error string","locations":null}]} +`) +}