graph-gophers / graphql-go

GraphQL server with a focus on ease of use
BSD 2-Clause "Simplified" License
4.65k stars 492 forks source link

Subscription fails with missing method error #612

Closed camopy closed 1 year ago

camopy commented 1 year ago

The SubscriptionResolver's method is failing with a missing method error when trying to return a channel instead of a pointer.

The issue is related to subscriptions and their implementation with a nested resolver structure.

So I'm a bit confused, do subscriptions only work on the "root" resolver?

type Subscription {
  onEventHappened: Event!
}

Or does it work with the following structure somehow?

type Subscription {
  marketSub: MarketSubscription!
}

type MarketSubscription {
   token: TokenUpdatedEvent!
}

type TokenUpdatedEvent {
    tokenUpdated: Token!
}
func (r *PublicRootResolver) Subscription() *PublicSubscriptionResolver {
    return r.PublicSubscriptionResolver
}

type PublicSubscriptionResolver struct {}

func (r *PublicSubscriptionResolver) MarketSub() *market.SubscriptionResolver {
    return market.NewSubscriptionResolver()
}
package market

type SubscriptionResolver struct {
    tokenSubscriber chan *tokenSubscriber
}

type tokenSubscriber struct {
    stop         <-chan struct{}
    tokenUpdated chan<- *TokenUpdatedEvent
}

func NewSubscriptionResolver() *SubscriptionResolver {
    return &SubscriptionResolver{}
}

// Project builds up if I use the following method signature:
// func (r *SubscriptionResolver) Token(ctx context.Context) *TokenUpdatedEvent {
func (r *SubscriptionResolver) Token(ctx context.Context) <-chan *TokenUpdatedEvent {
    c := make(chan *TokenUpdatedEvent)
    r.tokenSubscriber <- &tokenSubscriber{
        stop:         ctx.Done(),
        tokenUpdated: c,
    }
    return c
}

type TokenUpdatedEvent struct {
    token metadata.Token
}

func (r *TokenUpdatedEvent) TokenUpdated() *TokenResolver {
    return &TokenResolver{
        token:        r.token,
    }
}

The following error is thrown when building the project: PANIC panic {"panic": "<-chan *market.TokenUpdatedEvent does not resolve \"TokenUpdatedEvent\": missing method for field \"tokenUpdated\"\n\tused by (*market.SubscriptionResolver).Token\n\tused by (*v2.PublicRootResolver).MarketSub"}

The project builds up if I use the following method signature: func (r *SubscriptionResolver) Token(ctx context.Context) *TokenUpdatedEvent {

But afaik, the correct for subscriptions is to return a channel, but then it fails: func (r *SubscriptionResolver) Token(ctx context.Context) <-chan *TokenUpdatedEvent {

pavelnikolov commented 1 year ago

There is a channel only for the root level resolver. Any time this channel sends a message the entire response is sent to the client, e.g. {"data":"..."}. This is not an issue with the library but rather how subscriptions are handled.