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
685 stars 129 forks source link

Pass InitialPayload from Federated Subscriptions to Subgraphs #803

Open IsabelFreitas-catapult opened 4 months ago

IsabelFreitas-catapult commented 4 months ago

My client uses the initialPayload to pass custom header information to the websocket connection, I can intercept the payload at the federated level but it isn't being passed on to the subgraphs where I need it

cordjr commented 4 months ago

you wil needto store this information in context and then retrieve this and send through the subscriber , this is what worked for me at the time i needed. José Cordeiro de Oliveira junior Analista de Sistemas / Desenvolvedor

Em sex., 17 de mai. de 2024 às 12:57, Isabel F Freitas < @.***> escreveu:

My client uses the initialPayload to pass custom header information to the websocket connection, I can intercept the payload at the federated level but it isn't being passed on to the subgraphs where I need it

— Reply to this email directly, view it on GitHub https://github.com/wundergraph/graphql-go-tools/issues/803, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAFLEQDEMSUKAI75JMQOGDZCXWCXAVCNFSM6AAAAABH377ONWVHI2DSMVQWIX3LMV43ASLTON2WKOZSGMYDENJUHAZDMNQ . You are receiving this because you are subscribed to this thread.Message ID: @.***>

IsabelFreitas-catapult commented 4 months ago

@cordjr Thank you for getting back to me inws.go I have set up a the WithInitFunc HandleWebsocket that adds the values of the initialPayload to context, however after this point those values disappear from the context

func HandleWebsocket(done chan bool, errChan chan error, conn net.Conn,
    executorPool *subscription.ExecutorV2Pool, logger *slog.Logger) {
    defer func() {
        if err := conn.Close(); err != nil {
            logger.Error("http.HandleWebsocket(): could not close connection to client.", err)
        }
    }()

    websocket.Handle(
        done,
        errChan,
        conn,
        executorPool,
        websocket.WithProtocol(websocket.ProtocolGraphQLWS),
        websocket.WithInitFunc(func(ctx context.Context,
            initPayload websocket.InitPayload) (context.Context, error) {
            headers := http.Header{}
            initPayload.GetString("X-Email")
            headers.Add("X-Email", initPayload.GetString("X-Email"))
            ctx = context.WithValue(ctx, "headers", headers)
            return ctx, nil
        }),
        websocket.WithCustomSubscriptionUpdateInterval(50*time.Millisecond),
        websocket.WithCustomKeepAliveInterval(3600*time.Second),
    )
}

any chance you could share your implementation?

cordjr commented 4 months ago

Regard some compliance , no . Let me know the version graphql-tools so I can elaborate something for you . José Cordeiro de Oliveira junior Analista de Sistemas / Desenvolvedor

Em seg., 20 de mai. de 2024 às 13:52, Isabel F Freitas < @.***> escreveu:

@cordjr https://github.com/cordjr Thank you for getting back to me inws.go I have set up a the WithInitFunc HandleWebsocket that adds the values of the initialPayload to context, however after this point those values disappear from the context

func HandleWebsocket(done chan bool, errChan chan error, conn net.Conn, executorPool subscription.ExecutorV2Pool, logger slog.Logger) { defer func() { if err := conn.Close(); err != nil { logger.Error("http.HandleWebsocket(): could not close connection to client.", err) } }()

websocket.Handle( done, errChan, conn, executorPool, websocket.WithProtocol(websocket.ProtocolGraphQLWS), websocket.WithInitFunc(func(ctx context.Context, initPayload websocket.InitPayload) (context.Context, error) { headers := http.Header{} initPayload.GetString("X-Email") headers.Add("X-Email", initPayload.GetString("X-Email")) ctx = context.WithValue(ctx, "headers", headers) return ctx, nil }), websocket.WithCustomSubscriptionUpdateInterval(50time.Millisecond), websocket.WithCustomKeepAliveInterval(3600time.Second), ) }

any change you could share your implementation?

— Reply to this email directly, view it on GitHub https://github.com/wundergraph/graphql-go-tools/issues/803#issuecomment-2120402629, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAFLEVVR7ZLW5I5LHYM7DDZDHWYRAVCNFSM6AAAAABH377ONWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCMRQGQYDENRSHE . You are receiving this because you were mentioned.Message ID: @.***>

IsabelFreitas-catapult commented 4 months ago

github.com/wundergraph/graphql-go-tools v1.67.2 and the Handle function I am using is this one https://github.com/wundergraph/graphql-go-tools/blob/master/pkg/subscription/websocket/handler.go

cordjr commented 4 months ago

The version that I did the modification is diferent from yours but looking at this version I think you can add the following function to your gateway :

func OnBeforeStart(reqCtx context.Context, operation *graphql.Request) error { var headers = http.Header{} var someHeader = reqCtx.Value("someHeade").(string) headers.Add("someHeader", someHeader) operation.SetHeader(headers) return nil }

and then do the modification as bellow:.

func (g *Gateway) UpdateDataSources(newDataSourcesConfig []graphqlDataSource.Configuration) { ctx := context.Background() engineConfigFactory := graphql.NewFederationEngineConfigFactory(newDataSourcesConfig, graphqlDataSource.NewBatchFactory(), graphql.WithFederationHttpClient(g.httpClient), graphql.WithEngineOptions(graphql.WithDisableIntrospection(true)))

schema, err := engineConfigFactory.MergedSchema()
if err != nil {
   g.logger.Error("get schema:", log.Error(err))
   return
}

datasourceConfig, err := engineConfigFactory.EngineV2Configuration()
// puthis here to enable the hook
datasourceConfig.SetWebsocketBeforeStartHook(g)

The inici function you are passing is executed in the init pjhase of subscription, although the gateway does not pa trigger any subgraph at this phase. so when it comes the Start phase it triggers the the init and start message. So before this the hook is executed and we can take advantage of this to copy the values you put in context to the headers .

This is ugly but is what I could do.

I hope it helps

José Cordeiro de Oliveira junior Analista de Sistemas / Desenvolvedor

Em ter., 21 de mai. de 2024 às 13:55, Isabel F Freitas < @.***> escreveu:

github.com/wundergraph/graphql-go-tools v1.67.2 and the Handle function I am using is this one https://github.com/wundergraph/graphql-go-tools/blob/master/pkg/subscription/websocket/handler.go

— Reply to this email directly, view it on GitHub https://github.com/wundergraph/graphql-go-tools/issues/803#issuecomment-2122574510, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAFLEQWLEADGSTMSX447ILZDM75HAVCNFSM6AAAAABH377ONWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCMRSGU3TINJRGA . You are receiving this because you were mentioned.Message ID: @.***>

jensneuse commented 4 months ago

Just stepping into the discussion, you could use this test and debug through it to see how we're solving this problem in Cosmo Router to get some inspiration on how the library can be used: https://github.com/wundergraph/cosmo/blob/4077ab4a01f03c1c3dd7e6167255d3d8da80e3dc/router-tests/websocket_test.go#L406

cordjr commented 4 months ago

just a fix the function for the hook should be:

func (g Gateway) OnBeforeStart(reqCtx context.Context, operation graphql.Request) error { var headers = http.Header{} var someHeader = reqCtx.Value("someHeade").(string) headers.Add("someHeader", someHeader) operation.SetHeader(headers) return nil }

Thanks for sharing @jens José Cordeiro de Oliveira junior Analista de Sistemas / Desenvolvedor

Em qua., 22 de mai. de 2024 às 06:35, Jens Neuse @.***> escreveu:

Just stepping into the discussion, you could use this test and debug through it to see how we're solving this problem in Cosmo Router to get some inspiration on how the library can be used: https://github.com/wundergraph/cosmo/blob/4077ab4a01f03c1c3dd7e6167255d3d8da80e3dc/router-tests/websocket_test.go#L406

— Reply to this email directly, view it on GitHub https://github.com/wundergraph/graphql-go-tools/issues/803#issuecomment-2123901196, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAFLEV6PXGBZTO3UZPYZM3ZDQVATAVCNFSM6AAAAABH377ONWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCMRTHEYDCMJZGY . You are receiving this because you were mentioned.Message ID: @.***>