wundergraph / graphql-go-tools

GraphQL Router / API Gateway framework written in Golang, focussing on correctness, extensibility, and high-performance. Supports Federation v1 & v2, Subscriptions & more.
https://graphql-api-gateway.com
MIT License
682 stars 126 forks source link

Issue when trying to resolve implementation type of interface when a field does not exist #866

Closed hmajid2301 closed 3 days ago

hmajid2301 commented 1 month ago

Hi :wave:,

I think I have come across a bug in this library (please let me know if I am missing something and this is not the case).

Example Repository: https://gitlab.com/haseeb.majid1/graphql-minimal

TL;DR;

The bug seems to occur when I have an interface, and it is implemented and then extended by another service. If we try to fetch a field which was extended, but there is no data exists which includes that field.

We get an error Get \"\": unsupported protocol scheme \"\".

Version

 github.com/wundergraph/graphql-go-tools v1.67.2

Background

The repository, linked above, creates a minimal example to try to replicate a bug. I am noticing occurs with service(s) when I use federation.

Explanation

Let's have a look at an example, which may better explain the issue we are noticing (in this repository).

NOTE: When I say graphql gateway this is the service I built which uses this library.

In this example defined in servicea:

extend type Query {
  # ...
  randomItem: UserItem
}

interface UserItem {
  id: ID!
}

Then we have several implementations of that interface defined like so:

type UserItemA implements UserItem @key(fields: "id userID") {
  id: ID!
  userID: ID!
  actionA: String!
}

type UserItemB implements UserItem @key(fields: "id userID") {
  id: ID!
  userID: ID!
  actionB: String!
}

Then in another service, say serviceb, we extend one of these implementations like so:

extend type UserItemA @key(fields: "id userID") {
  id: ID! @external
  userID: ID! @external
  reason: ID!
}

If we send a query to see which types exist:

query MyQuery1 {
  randomItems {
    __typename
  }
}

Which returns:

{
  "data": {
    "randomItem": {
      "__typename": "UserItemB"
    }
  }
}

As we can see, we only have types of UserItemB. When we send a query to get the reason:

query MyQuery2 {
  randomItems {
    ... on UserItemA {
      reason
    }
  }
}

This is when the error is thrown by the GraphQL gateway. Where this library is used. Looking at the error thrown by the GraphQL gateway (which is using this library) I see:

Get \"\": unsupported protocol scheme \"\"

Where the error is thrown when we call Execute function on ExecutionEngineV2. The relevant code in our GraphQL gateway looks like so (this is HTTP handler function):

var gqlRequest graphql.Request
if err := graphql.UnmarshalHttpRequest(r, &gqlRequest); err != nil {
    // handle error
}

// ...
resultWriter := graphql.NewEngineResultWriterFromBuffer(buf)
err := g.engine.Execute(r.Context(), &gqlRequest, &resultWriter, graphql.WithAdditionalHttpHeaders(headers))
// ...

Where the engine is of type:

engine         *graphql.ExecutionEngineV2

Code in Library

From what I can see, the error happens within the method resolveObject in pkg/engine/resolve/resolve.go. I noticed that this part (the error, and a null is returned) of the code is being called pkg/engine/resolve/inputtemplate.go in the Render method.

if errors.Is(err, setTemplateOutputNull) {
    preparedInput.Reset()
    preparedInput.WriteBytes(literal.NULL)
    return nil
}

Where the error is set in this case:

case ObjectVariableKind:
    err = i.renderObjectVariable(ctx.Context(), data, segment, preparedInput)

Reproduce

  1. Start up both services in this repository
cd servicea
PORT=8095 go run server.go

# In another terminal

cd serviceb
PORT=8096 go run server.go
  1. Point your GraphQL gateway to these services, i.e. http://localhost:8095/query, to enable federation.
  2. Go to a GraphQL playground and run this query
query MyQuery2 {
  randomItem {
    ... on UserItemA {
      reason
    }
  }
}
  1. You should see this error from the output of the GraphQL gateway:
Get \"\": unsupported protocol scheme \"\"

Please let me know if you need additional information! Happy to help where I can.

Thanks

devsergiy commented 1 month ago

Hi @hmajid2301

v1.67.2 is no longer maintained version

Please try v2.0.0-rc.68

With this example

hmajid2301 commented 1 month ago

Okay, thanks, I will try to do that next week and see if that resolves the issue.

hmajid2301 commented 3 days ago

I think this resolved it, I'm hitting other issues now :thinking: (around http headers). But this looks to be working.