Skip to content

Adding "Subscribe" field to subscription definitions #242

Closed
@robbawebba

Description

@robbawebba

I'm currently implementing a GraphQL subscription server and I'm interested in adding subscription logic to each subscription definition to use with my PubSub manager. Is it possible to add a custom field to a subscription definition that I can use to pass data/functions around? If not, would the core team consider this as a possible enhancement to the way subscriptions work?

The idea is to have a field similar to Resolve (possiblly called Subscribe) that will be accesible by any PubSub system that contains a function. This function would be responsible for the logic that defines how a subscription listens for events based on the client's query and publishes updates to the client. It's implementation and requirements, similar to the Resolve function, would be pretty relaxed and would rely on the developer to fill the function with the logic that they need to work with their data layer. So when a developer is definining subscriptions and needs a place to create query-specific logic for listening for events and publishing changes, they will be able to define that along side the rest of the subscription definition.

Lastly, the PubSub manager will be able to use this function when creating a new instance of a subscription.

Below is an example of what I'm trying to accomplish. This particular implementation of the proposed Subscribe field listens for changes to a RethinkDB database based on the contactID provided from the client's subscription query. After the change listener is set up, When a change to the database is received, the changes are published to the PubSub manager.

type dbChange struct {
	NewVal interface{} `gorethink:"new_val"`
	OldVal interface{} `gorethink:"old_val"`
}

var rootSubscription = graphql.NewObject(graphql.ObjectConfig{
	Name: "rootSubscription",
	Fields: graphql.Fields{
		"contactChanged": &graphql.Field{
			Type: contact,
			Args: graphql.FieldConfigArgument{
				"contactID": &graphql.ArgumentConfig{
					Type: graphql.String,
				},
			},
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return p.Info.RootValue, nil
			},
			Subscribe: func(params graphql.ResolveParams) error {
				ID := params.Args["contactID"].(string)
				contactCursor, err := gorethink.DB("ContactsApp").
					Table("Contacts").
					Get(ID).
					Changes().
					Run(db.Session)
				if err != nil {
					fmt.Errorf(`Error reading database: %v`, err)
					return err
				}
				contactChanges := make(chan dbChange)
				contactCursor.Listen(contactChanges)
				fmt.Println("Listening for changes")

				for change := range contactChanges {
					subManager.publish("CONTACT_CHANGED", change)
				}
			},
		},
	},
})

My goal is to mimic the functionality of Apollo GraphQL's graphql-subscriptions NPM package that relies on a subscribe function associated with each subscription definition to set up the subscription:

const SOMETHING_CHANGED_TOPIC = 'something_changed';

export const resolvers = {
  Subscription: {
    somethingChanged: {
      subscribe: () => pubsub.asyncIterator(SOMETHING_CHANGED_TOPIC),
    },
  },
}

If anyone has any insight on custom fields in the subscription definition, or about this possible enhancement, I would love some feedback. Thanks for listening, and thanks for creating this library!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions