Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat(GraphQL): This PR allows to return errors from custom REST endpoint. #6604

Merged
merged 16 commits into from
Oct 5, 2020
41 changes: 41 additions & 0 deletions graphql/e2e/custom_logic/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,26 @@ func getDefaultResponse() []byte {
return []byte(resTemplate)
}

func getRestError(w http.ResponseWriter, err []byte) {
w.WriteHeader(http.StatusBadRequest)
check2(w.Write(err))
}

func getFavMoviesErrorHandler(w http.ResponseWriter, r *http.Request) {
err := verifyRequest(r, expectedRequest{
method: http.MethodGet,
urlSuffix: "/0x123?name=Author&num=10",
body: "",
headers: nil,
})
if err != nil {
check2(w.Write([]byte(err.Error())))
return
}

getRestError(w, []byte(`{"errors":[{"message": "Rest API returns Error for myFavoriteMovies query","locations": [ { "line": 5, "column": 4 } ],"path": ["Movies","name"]}]}`))
}

func getFavMoviesHandler(w http.ResponseWriter, r *http.Request) {
err := verifyRequest(r, expectedRequest{
method: http.MethodGet,
Expand Down Expand Up @@ -398,6 +418,20 @@ func favMoviesCreateHandler(w http.ResponseWriter, r *http.Request) {
]`)))
}

func favMoviesCreateErrorHandler(w http.ResponseWriter, r *http.Request) {
err := verifyRequest(r, expectedRequest{
method: http.MethodPost,
urlSuffix: "/favMoviesCreateError",
body: `{"movies":[{"director":[{"name":"Dir1"}],"name":"Mov1"},{"name":"Mov2"}]}`,
headers: nil,
})
if err != nil {
check2(w.Write([]byte(err.Error())))
return
}
getRestError(w, []byte(`{"errors":[{"message": "Rest API returns Error for FavoriteMoviesCreate query"}]}`))
}

func favMoviesCreateWithNullBodyHandler(w http.ResponseWriter, r *http.Request) {
err := verifyRequest(r, expectedRequest{
method: http.MethodPost,
Expand Down Expand Up @@ -836,6 +870,10 @@ func userNameHandler(w http.ResponseWriter, r *http.Request) {
nameHandler(w, r, &inputBody)
}

func userNameErrorHandler(w http.ResponseWriter, r *http.Request) {
getRestError(w, []byte(`{"errors":[{"message": "Rest API returns Error for field name"}]}`))
}

func userNameWithoutAddressHandler(w http.ResponseWriter, r *http.Request) {
expectedRequest := expectedRequest{
body: `{"uid":"0x5"}`,
Expand Down Expand Up @@ -1210,6 +1248,7 @@ func main() {

// for queries
http.HandleFunc("/favMovies/", getFavMoviesHandler)
http.HandleFunc("/favMoviesError/", getFavMoviesErrorHandler)
http.HandleFunc("/favMoviesPost/", postFavMoviesHandler)
http.HandleFunc("/favMoviesPostWithBody/", postFavMoviesWithBodyHandler)
http.HandleFunc("/verifyHeaders", verifyHeadersHandler)
Expand All @@ -1218,6 +1257,7 @@ func main() {

// for mutations
http.HandleFunc("/favMoviesCreate", favMoviesCreateHandler)
http.HandleFunc("/favMoviesCreateError", favMoviesCreateErrorHandler)
http.HandleFunc("/favMoviesUpdate/", favMoviesUpdateHandler)
http.HandleFunc("/favMoviesDelete/", favMoviesDeleteHandler)
http.HandleFunc("/favMoviesCreateWithNullBody", favMoviesCreateWithNullBodyHandler)
Expand All @@ -1232,6 +1272,7 @@ func main() {

// for testing single mode
http.HandleFunc("/userName", userNameHandler)
http.HandleFunc("/userNameError", userNameErrorHandler)
http.HandleFunc("/userNameWithoutAddress", userNameWithoutAddressHandler)
http.HandleFunc("/checkHeadersForUserName", userNameHandlerWithHeaders)
http.HandleFunc("/car", carHandler)
Expand Down
187 changes: 184 additions & 3 deletions graphql/e2e/custom_logic/custom_logic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ func TestCustomQueryWithNonExistentURLShouldReturnError(t *testing.T) {
require.Equal(t, x.GqlErrorList{
{
Message: "Evaluation of custom field failed because external request returned an " +
"error: unexpected status code: 404 for field: myFavoriteMovies within" +
"error: unexpected Error with status code: 404 for field: myFavoriteMovies within" +
" type: Query.",
Locations: []x.Location{{Line: 3, Column: 3}},
},
Expand Down Expand Up @@ -557,10 +557,10 @@ func TestCustomQueryShouldPropagateErrorFromFields(t *testing.T) {

expectedErrors := x.GqlErrorList{
&x.GqlError{Message: "Evaluation of custom field failed because external request " +
"returned an error: unexpected status code: 404 for field: cars within type: Person.",
"returned an error: unexpected Error with status code: 404 for field: cars within type: Person.",
Locations: []x.Location{{Line: 6, Column: 4}}},
&x.GqlError{Message: "Evaluation of custom field failed because external request returned" +
" an error: unexpected status code: 404 for field: bikes within type: Person.",
" an error: unexpected Error with status code: 404 for field: bikes within type: Person.",
Locations: []x.Location{{Line: 9, Column: 4}}},
}
require.Contains(t, result.Errors, expectedErrors[0])
Expand Down Expand Up @@ -2808,3 +2808,184 @@ func TestCustomDQL(t *testing.T) {
]
}`, string(result.Data))
}

func TestCustomGetQuerywithRESTError(t *testing.T) {
schema := customTypes + `
type Query {
myFavoriteMovies(id: ID!, name: String!, num: Int): [Movie] @custom(http: {
url: "http://mock:8888/favMoviesError/$id?name=$name&num=$num",
method: "GET"
})
}`
updateSchemaRequireNoGQLErrors(t, schema)
time.Sleep(2 * time.Second)

query := `
query {
myFavoriteMovies(id: "0x123", name: "Author", num: 10) {
id
name
director {
id
name
}
}
}`
params := &common.GraphQLParams{
Query: query,
}

result := params.ExecuteAsPost(t, alphaURL)
require.Equal(t, x.GqlErrorList{
{
Message: "Rest API returns Error for myFavoriteMovies query",
Locations: []x.Location{{Line: 5, Column: 4}},
Path: []interface{}{"Movies", "name"},
},
}, result.Errors)

}

func TestCustomFieldsWithRestError(t *testing.T) {
schema := `
type Car @remote {
id: ID!
name: String!
}

type User {
id: String! @id @search(by: [hash, regexp])
name: String
@custom(
http: {
url: "http://mock:8888//userNameError"
method: "GET"
body: "{uid: $id}"
mode: SINGLE,
}
)
age: Int! @search
cars: Car
@custom(
http: {
url: "http://mock:8888/cars"
method: "GET"
body: "{uid: $id}"
mode: BATCH,
}
)
}
`

updateSchemaRequireNoGQLErrors(t, schema)
time.Sleep(2 * time.Second)

params := &common.GraphQLParams{
Query: `mutation addUser {
addUser(input: [{ id:"0x1", age: 10 }]) {
user {
id
age
}
}
}`,
}

result := params.ExecuteAsPost(t, alphaURL)
common.RequireNoGQLErrors(t, result)

queryUser := `
query ($id: String!){
queryUser(filter: {id: {eq: $id}}) {
id
name
age
cars{
name
}
}
}`

params = &common.GraphQLParams{
Query: queryUser,
Variables: map[string]interface{}{"id": "0x1"},
}

result = params.ExecuteAsPost(t, alphaURL)

expected := `
{
"queryUser": [
{
"id": "0x1",
"name": null,
"age": 10,
"cars": {
"name": "car-0x1"
}
}
]
}`

require.Equal(t, x.GqlErrorList{
{
Message: "Rest API returns Error for field name",
},
}, result.Errors)

require.JSONEq(t, expected, string(result.Data))

}

func TestCustomPostMutationWithRESTError(t *testing.T) {
schema := customTypes + `
input MovieDirectorInput {
id: ID
name: String
directed: [MovieInput]
}
input MovieInput {
id: ID
name: String
director: [MovieDirectorInput]
}
type Mutation {
createMyFavouriteMovies(input: [MovieInput!]): [Movie] @custom(http: {
url: "http://mock:8888/favMoviesCreateError",
method: "POST",
body: "{ movies: $input}"
})
}`
updateSchemaRequireNoGQLErrors(t, schema)
time.Sleep(2 * time.Second)

params := &common.GraphQLParams{
Query: `
mutation createMovies($movs: [MovieInput!]) {
createMyFavouriteMovies(input: $movs) {
id
name
director {
id
name
}
}
}`,
Variables: map[string]interface{}{
"movs": []interface{}{
map[string]interface{}{
"name": "Mov1",
"director": []interface{}{map[string]interface{}{"name": "Dir1"}},
},
map[string]interface{}{"name": "Mov2"},
}},
}

result := params.ExecuteAsPost(t, alphaURL)
require.Equal(t, x.GqlErrorList{
{
Message: "Rest API returns Error for FavoriteMoviesCreate query",
},
}, result.Errors)

}
Loading