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

Fix XS missing 'ctx' into context #73

Merged
merged 6 commits into from Jun 21, 2020
Merged

Fix XS missing 'ctx' into context #73

merged 6 commits into from Jun 21, 2020

Conversation

Hugome
Copy link
Collaborator

@Hugome Hugome commented Apr 25, 2020

Fix #72

@shawnmcknight
Copy link
Member

I'm trying to get myself a bit more familiar with subscriptions and web sockets here, but I have a couple thoughts so far:

                  : {
                      service: connection.$service,
                    };
              },
              subscriptions: {
                onConnect: connectionParams => ({
                  ...connectionParams,
                  $service: this,
                }),
              },

In inspecting what happens here, the onConnect handler will add $service to the graphql context. However, this is not available at connection.$service later, but is instead available at connection.context.$service. Nothing appears to actually make use of this in the rest of the code, but I think this is incorrect and plays into my next thought.

  1. Perhaps instead of establishing a new Context instance in the context assignment, it should instead be created when the subscription connects. Something like you already did, but add $ctx to the result of onConnect and then set ctx to connection.context.$ctx in the object construction.

  2. I think setting the empty dataLoaders Map in both context objects would be important. If a child resolver had the dataLoader flag set, we would end up failing similarly to ctx being missing.

  3. If we create a new Context here, it would seem that the asyncIteratorResolver could use ctx.call instead of broker.call which is a little smoother in my opinion.

  4. If the WS logic is bypassing moleculer-web's assignment of the $ internal variables and creation of context, are we ultimately bypassing everything else moleculer-web abstracts away? That is, are we bypassing all of the lifecycles like authentication and authorization? I'm guessing we are, which is concerning. I'm not sure if there's a way to remedy that, but if it can be remedied, is there a manner in which the creation of context can be moved into moleculer-web's functionality in some way, similar to how the context is added to the req by moleculer-web?

As I mentioned in my opening, I'm not terribly familiar with GraphQL subscriptions or web sockets in general as I've not used either, but I wanted to get my initial thoughts on the table. I'll dig in some more.

@shawnmcknight
Copy link
Member

If the WS logic is bypassing moleculer-web's assignment of the $ internal variables and creation of context, are we ultimately bypassing everything else moleculer-web abstracts away? That is, are we bypassing all of the lifecycles like authentication and authorization? I'm guessing we are, which is concerning. I'm not sure if there's a way to remedy that, but if it can be remedied, is there a manner in which the creation of context can be moved into moleculer-web's functionality in some way, similar to how the context is added to the req by moleculer-web?

So, after digging in a bit here, that's where onConnect is supposed to come into play. If you need custom authentication/authorization logic, that needs to occur here. It appears that you can intercept http headers for something like a token. So, I'm thinking in order to solve that, a different injectable function would need to be provided that could run as part of the connection lifecycle. Clearly that's out of scope for this PR.

With that in mind, I am more of the opinion that establishing context in onConnect is a more suitable location. Also, as I dig a bit more into how the service broker creates context, it uses the broker's factory method to do it, which I believe is important for custom contexts (we use one in our environment). so it would be risky to not ensure that is used. So maybe @icebob should weigh in here if there is a better way, but I'm thinking ctx = this.broker.ContextFactory.create(this, null, {}, {}); might be the more appropriate way to generate context at this level.

@icebob
Copy link
Member

icebob commented Apr 26, 2020

Yes, using the ContextFactory.create is the right way to create context. Moreover, if you don't define Endpoint it maybe causes problems. But you can't because the Context created outside actions. Maybe we can create an internal action like moleculer-web has also a rest internal action which is called with req & res. Although, I'm not familiar with Apollo subscription.

@Hugome
Copy link
Collaborator Author

Hugome commented Apr 27, 2020

@shawnmcknight

Perhaps instead of establishing a new Context instance in the context assignment, it should instead be created when the subscription connects. Something like you already did, but add $ctx to the result of onConnect and then set ctx to connection.context.$ctx in the object construction.

I think setting the empty dataLoaders Map in both context objects would be important. If a child resolver had the dataLoader flag set, we would end up failing similarly to ctx being missing.

If we create a new Context here, it would seem that the asyncIteratorResolver could use ctx.call instead of broker.call which is a little smoother in my opinion.

Yep you are totally right with these points.

@icebob

Maybe we can create an internal action like moleculer-web has also a rest internal action which is called with req & res. Although, I'm not familiar with Apollo subscription.

I think it can do the job quite well.

I have change the code, let me know what you think.
It use this idea of @icebob and improve the context (Now you can have access to the query params passed to the upgrade request if your need in you authentification/autorization)
And apply @shawnmcknight improvement on connection.context.$ctx/dataLoaders/asyncIteratorResolver

@icebob
Copy link
Member

icebob commented Apr 28, 2020

@shawnmcknight could you help to check it?

src/service.js Outdated Show resolved Hide resolved
src/service.js Outdated Show resolved Hide resolved
src/service.js Outdated Show resolved Hide resolved
@icebob
Copy link
Member

icebob commented Jun 18, 2020

What's the status of this PR?

Copy link
Member

@shawnmcknight shawnmcknight left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I apologize for the delay in this review. After the latest batch of changes, shouldn't the constuction of the Apollo Context for the WS connection no longer be looking at the .socket property for $params and $ctx, similar to how its not using it for $service?

src/service.js Outdated Show resolved Hide resolved
src/service.js Outdated Show resolved Hide resolved
@Hugome
Copy link
Collaborator Author

Hugome commented Jun 21, 2020

Absolutely right, now fixed

test/unit/service.spec.js Outdated Show resolved Hide resolved
@Hugome
Copy link
Collaborator Author

Hugome commented Jun 21, 2020

Sorry I forgot to commit test file, done.

Copy link
Member

@shawnmcknight shawnmcknight left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Merging 🤖

@shawnmcknight shawnmcknight merged commit 6bf4ced into moleculerjs:master Jun 21, 2020
@icebob
Copy link
Member

icebob commented Jun 21, 2020

Awesome, thanks @shawnmcknight & @Hugome!

@Hugome Hugome deleted the fix-ws-ctx branch August 30, 2020 12:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Subscription and service level resolver
3 participants