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

introduce GraphQLExecutorWithSubscriptions #47

Closed
wants to merge 9 commits into from

Conversation

DxCx
Copy link

@DxCx DxCx commented Feb 18, 2017

Hey,

I've refactored graphql-subscriptions so the execution logic will be isolated then the SubscriptionManager.
With this executor we will support subscriptions for the new graphql-server-ws package.

This PR also adds support for query/mutation.

TODO:

  • Update README.md add example.

package.json Outdated
@@ -8,7 +8,8 @@
"url": "/~https://github.com/apollostack/graphql-subscriptions.git"
},
"dependencies": {
"es6-promise": "^3.2.1"
"es6-promise": "^3.2.1",
"graphql-server-observable": "file://../graphql-server/packages/graphql-server-observable"
Copy link
Author

Choose a reason for hiding this comment

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

pending merging of apollographql/apollo-server#308

@stubailo
Copy link
Contributor

Why does this code need to be inside this package? Can't it just go into your GraphQL-server-ws package?

@DxCx
Copy link
Author

DxCx commented Feb 22, 2017

I can wrap it the other way around and give it another package inside graphql-server,
Howerver:
A. I spoke with @helfer before and we both agreed we dont need to introduce another package but just patch the existing package
B. Performance-wise, you will have more logic running that is redundant

@stubailo
Copy link
Contributor

Is the main goal here to make the subscription return an observable instead of the callback style? Or does it also do something else?

@stubailo
Copy link
Contributor

After looking at the code I think it could be a really great change, but it would be a lot easier to look at it if there was a description about what it is trying to achieve. I agree it is a good idea to have an execution function that decides whether to run a subscription or a static query, but it wasn't clear at first that this is what the PR is doing.

@DxCx
Copy link
Author

DxCx commented Feb 22, 2017

Sorry @stubailo
Well, yeah it has 2 goals:

  1. Allow engine code execute staticlly or reactive.
  2. Export functionality of the engine alone, so graphql-server-ws will be able to support the exisiting pubsub code.

This way people can migrate easily from running on both http and websocket to run all operations on a single websocket connection.

@stubailo
Copy link
Contributor

Is there any reason it's split into two steps like that? Why not:

graphqlExecutorWithSubscriptions({
  pubsub,
  setupFunctions,
  schema,
  ...
}

Right now you have to initialize the executor and then call execute but it could just be one function I think?

@DxCx
Copy link
Author

DxCx commented Feb 22, 2017

But the idea is to be comeptiable with graphql execute engine step.
So the GraphQLWithSubscription should be constructed with what makes it a special engine.
(Which is the pubsub related stuff)
Then it will export a function that accepts the exact same arguments as execute gets (and schema being one of them)

@DxCx
Copy link
Author

DxCx commented Feb 22, 2017

If the main goal was to just introduce obeservable that was probably right, but as ive said i wanted the code to be more reusable in general..

@stubailo
Copy link
Contributor

But it still won't be a simple replacement right, since graphql returns a promise and this returns an observable. However, if that's your goal I think it would be best for GraphQLExecutorWithSubscriptions to return a function rather than an object, like so:

const graphql = createGraphQLExecutorWithSubscriptions(...);

const resultObservable = graphql(...);

Then it will be even more interchangeable?

@DxCx
Copy link
Author

DxCx commented Feb 23, 2017

Well, the same interface, but instead of a promise, an observable, so more then one value can be emitted.

Why would returning a factory will be better?
Essentially typescript compiler will convert class to functions anyway, so why is that better?

@stubailo
Copy link
Contributor

Because it's more similar to the original graphql API? graphql-js exports a function, so this would be more consistent with how people are used to consuming that API. (In your case I think you're creating a class with one method on it, which is a pretty different API)

@DxCx
Copy link
Author

DxCx commented Feb 23, 2017 via email

@stubailo
Copy link
Contributor

OK I think that's fine - I think @Urigo should review.

My last opinion here would be that GraphQLExecutorWithSubscriptions should ideally take an entire SubscriptionManager object as one argument, so that we don't have to document those arguments twice (since it takes basically the same things).

@DxCx
Copy link
Author

DxCx commented Feb 23, 2017 via email

@DxCx
Copy link
Author

DxCx commented Mar 29, 2017

this PR is ready to be merged. 👍

this.pubsub = options.pubsub;
}

public executeReactive(
Copy link
Contributor

@NeoPhi NeoPhi Apr 3, 2017

Choose a reason for hiding this comment

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

Feels like this should be using an object to pass in arguments. Likewise for execute below.

Copy link
Author

Choose a reason for hiding this comment

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

The idea is to have the same signature as original's graphql execute..

@@ -36,13 +21,15 @@ export class PubSub implements PubSubEngine {
}

public publish(triggerName: string, payload: any): boolean {
this.ee.emit(triggerName, payload);
process.nextTick(() => this.ee.emit(triggerName, payload));
Copy link
Contributor

Choose a reason for hiding this comment

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

Comment about why the nextTick is needed.

Copy link
Author

Choose a reason for hiding this comment

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

I dont remember the exact issue, but it is related to how the tests assume data is handled.. i can dig in again

.subscribe({
next: (v) => {
resolve(v)
process.nextTick(() => sub.unsubscribe());
Copy link
Contributor

Choose a reason for hiding this comment

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

Comment about why nextTick is needed.

Copy link
Author

Choose a reason for hiding this comment

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

Because you want to make sure sub is resolved with a value.

resolve(v)
process.nextTick(() => sub.unsubscribe());
},
error: (e) => reject(e),
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we also have to unsubscribe in the error case?

Copy link
Author

Choose a reason for hiding this comment

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

Thats on the observer's duty, it might just unsubscribe or handle the error if it wants too, but we shouldn't unsubscribe for the user

@DxCx
Copy link
Author

DxCx commented May 15, 2017

@Urigo you forgot about this PR that addes GraphQLExecutorWithSubscriptions.

@Urigo
Copy link
Contributor

Urigo commented May 16, 2017

@DxCx I have not :) please check out my comment here - apollographql/subscriptions-transport-ws#108 (comment)

@DxCx
Copy link
Author

DxCx commented May 18, 2017

well, looks like executor pattern was removed in (apollographql/subscriptions-transport-ws#133) which means there is not reason to keep that PR..

@DxCx DxCx closed this May 18, 2017
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.

5 participants