Giter Club home page Giter Club logo

Comments (17)

andrew-hamilton-dev avatar andrew-hamilton-dev commented on March 28, 2024 5

I was having the same issue with [Object Object] as @joefru but I was able to resolve it by playing around with the package versions in the dependency versions. Below are the versions i ended up with to have it working. Might help you out @joefru.

"dependencies": {
    "@nestjs/common": "^4.5.9",
    "@nestjs/core": "^4.5.10",
    "@nestjs/graphql": "^2.0.0",
    "apollo-server-express": "^1.3.2",
    "graphql": "0.11.7",
    "graphql-subscriptions": "^0.5.6",
    "graphql-tools": "^2.19.0",
    "reflect-metadata": "^0.1.12",
    "rxjs": "^5.5.6",
    "subscriptions-transport-ws": "^0.9.5",
    "typescript": "^2.6.2",
    "ws": "^4.0.0"
  },
  "devDependencies": {
    "@types/node": "^9.4.0",
    "ts-node": "^4.1.0"
  }

from graphql.

Stradivario avatar Stradivario commented on March 28, 2024 2

I am out will ban nest community for sure

from graphql.

kamilmysliwiec avatar kamilmysliwiec commented on March 28, 2024

Hi @joefru,
I'm glad that you enjoy the project & and happy about the sponsor idea 🙂
Have you created the subscriptions endpoint in the same way as explained here? https://dev-blog.apollodata.com/tutorial-graphql-subscriptions-server-side-e51c32dc2951 (WebSocket Transport for Subscriptions)

from graphql.

joefru avatar joefru commented on March 28, 2024

I did happen to read that article. I'm wondering how to include the following code in 'the nest way'...

// Wrap the Express server
const ws = createServer(server);
ws.listen(PORT, () => {
  console.log(`GraphQL Server is now running on http://localhost:${PORT}`);
  // Set up the WebSocket for handling GraphQL subscriptions
  new SubscriptionServer({
    execute,
    subscribe,
    schema
  }, {
    server: ws,
    path: '/subscriptions',
  });
});

I tried something like this:

@WebSocketGateway({ port: process.env.PORT || 3000, namespace: "subscriptions" })
export class SubscriptionGateway implements OnGatewayInit {

	constructor(private graphQLFactory: GraphQLFactory) {}
	
	afterInit(server: any) {
		const schema = this.createSchema();

		new SubscriptionServer({
			execute,
			subscribe,
			schema
		}, {
			server: server,
			path: "/subscriptions",
		});
	}

	createSchema() {
		const typeDefs = this.graphQLFactory.mergeTypesByPaths("./**/*.graphql");

		return this.graphQLFactory.createSchema({ typeDefs });
	}
}

But that yields the following build-time error: Error: listen EADDRINUSE :::3000. When I switch to port 3001, it compiles but then I get the following error in browser console:

WebSocket connection to 'ws://localhost:3001/subscriptions' failed: Connection closed before receiving a handshake response

from graphql.

kamilmysliwiec avatar kamilmysliwiec commented on March 28, 2024

Hi @joefru,
I think you should avoid using @Gateway() here, let's make use of an async component instead. Register a SUBSCRIPTION_SERVER somewhere, for example inside the AppModule:

components: [
    {
      provide: SUBSCRIPTION_SERVER,
      useFactory: async () => {
        const server = createServer();
        return await new Promise((resolve) => server.listen(PORT, resolve));
      },
    }
  ]

Then inject this component into module class:

export class ApplicationModule implements NestModule {
  constructor(
    private readonly graphQLFactory: GraphQLFactory,
    @Inject(SUBSCRIPTION_SERVER) private readonly ws,
  ) {}

  /// rest of code
}

Afterwards, create instance of SubscriptionServer:

  configure(consumer: MiddlewaresConsumer) {
    const schema = this.createSchema();
    this.initSubscriptionServer(schema);

    consumer
      .apply(graphiqlExpress({
        endpointURL: "/graphql", 
        subscriptionsEndpoint: `ws://localhost:${process.env.PORT || 3000}/subscriptions`
      }))
      .forRoutes({path: "/graphiql", method: RequestMethod.GET})
      .apply(graphqlExpress(req => ({schema, rootValue: req})))
      .forRoutes({path: "/graphql", method: RequestMethod.ALL});
  }

  initSubscriptionServer(schema) {
    new SubscriptionServer({ execute, subscribe, schema}, {
	server: this.ws,
	path: "/subscriptions",
    });
  }

That's all. Remember to kill server (ws instance) using OnModuleDestroy hook.

from graphql.

joefru avatar joefru commented on March 28, 2024

First of all, thanks for the help and quick responses. Unfortunately, I still think something is missing. I followed your directions using the nest graphql-apollo example for simplicity's sake, and I get these warnings:

(node:71978) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): TypeError: Cannot convert undefined or null to object
(node:71978) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

When trying to access GraphiQL on localhost, the browser churns for several minutes, and eventually I get ERR_CONNECTION_REFUSED. Any thoughts?

from graphql.

kamilmysliwiec avatar kamilmysliwiec commented on March 28, 2024

Will try to reproduce this locally

from graphql.

kamilmysliwiec avatar kamilmysliwiec commented on March 28, 2024

Could you provide a little bit more code? What actually have you changed? Did you add a snippet that I shared with your or sth more?

from graphql.

joefru avatar joefru commented on March 28, 2024

I cloned the graphql-apollo example and contained all changes within app.module.ts:

import {
  Inject,
  Module,
  MiddlewaresConsumer,
  NestModule,
  RequestMethod,
} from '@nestjs/common';
import { createServer } from 'http';
import { graphqlExpress, graphiqlExpress } from 'apollo-server-express';
import { GraphQLModule, GraphQLFactory } from '@nestjs/graphql';
import { SubscriptionServer } from 'subscriptions-transport-ws';
import { execute, subscribe } from 'graphql';
import { CatsModule } from './cats/cats.module';

@Module({
  components: [
    {
      provide: "SUBSCRIPTION_SERVER",
      useFactory: async () => {
        const server = createServer();

        return new Promise((resolve) => server.listen(process.env.PORT || 3000, resolve));
      },
    }
  ],
  imports: [CatsModule, GraphQLModule],
})
export class ApplicationModule implements NestModule {
  constructor(private readonly graphQLFactory: GraphQLFactory, @Inject("SUBSCRIPTION_SERVER") private readonly ws) {}

  configure(consumer: MiddlewaresConsumer) {
    const schema = this.createSchema();

    this.initSubscriptionServer(schema);

    consumer
      .apply(graphiqlExpress({
        endpointURL: '/graphql', 
        subscriptionsEndpoint: `ws://localhost:${process.env.PORT || 3000}/subs`
      }))
      .forRoutes({ path: '/graphiql', method: RequestMethod.GET })
      .apply(graphqlExpress(req => ({ schema, rootValue: req })))
      .forRoutes({ path: '/graphql', method: RequestMethod.ALL });
  }

  createSchema() {
    const typeDefs = this.graphQLFactory.mergeTypesByPaths('./**/*.graphql');
    const schema = this.graphQLFactory.createSchema({ typeDefs });
    return this.graphQLFactory.createSchema({ typeDefs });
  }

  initSubscriptionServer(schema) {
    const ss = new SubscriptionServer({execute, subscribe, schema}, {
      server: this.ws,
      path: "/subs",
    });
  }

  onModuleDestroy() {
    this.ws.close();
  }
}

from graphql.

kamilmysliwiec avatar kamilmysliwiec commented on March 28, 2024

@joefru I'm sorry.. It was my mistake 🙁 Let's use code below instead:

{
      provide: 'SUBSCRIPTION_SERVER',
      useFactory: () => {
        const server = createServer();
        return new Promise(resolve => server.listen(process.env.PORT || 3000, () => resolve(server)));
      },
},

from graphql.

joefru avatar joefru commented on March 28, 2024

Making progress... That change let's me successfully create the subscription server. I still can't get a subscription to listen. I have this:

cats.resolvers.ts

import { Component, UseGuards } from '@nestjs/common';
import { Query, Mutation, Resolver, Subscription } from '@nestjs/graphql';

import { Cat } from './interfaces/cat.interface';
import { CatsService } from './cats.service';
import { CatsGuard } from './cats.guard';
import { PubSub } from 'graphql-subscriptions';

const pubsub = new PubSub();

@Resolver('Cat')
export class CatsResolvers {
  constructor(private readonly catsService: CatsService) {}

  @Query()
  @UseGuards(CatsGuard)
  async getCats() {
    return await this.catsService.findAll();
  }

  @Query('cat')
  async findOneById(obj, args, context, info): Promise<Cat> {
    const { id } = args;
    return await this.catsService.findOneById(+id);
  }

  @Mutation('createCat')
  async create(obj, args, context, info): Promise<Cat> {
    const cat = await this.catsService.create(args.name);

    pubsub.publish('catCreated', {catCreated: cat});

    return cat;
  }

  @Subscription('catCreated')
  catCreated() {
    return {
      subscribe: () => pubsub.asyncIterator('catCreated'),
    };
  }
}

cats.types.graphql

type Query {
  getCats: [Cat]
  cat(id: ID!): Cat
  catByHumanId(id: ID!): Cat
}

type Mutation {
  createCat(name: String): Cat
}

type Subscription {
  catCreated: Cat
}

type Cat {
  id: Int
  name: String
  age: Int
  humanId: Int
}

When I run the following subscription in GraphiQL:

subscription catname {
  catCreated {
    name
  }
}

It displays [object Object] in the results window. It looks like it quickly flashes Your subscription data will appear here after server publication! and then immediately changes to [object Object]. Similar behavior was described in this thread. Unfortunately, the suggestions in that discussion have not led me to a solution.

Ultimately, I'd love to see the graphql-apollo example be extended to include a simple working subscription like catCreated that I can run from GraphiQL.

from graphql.

kamilmysliwiec avatar kamilmysliwiec commented on March 28, 2024

I updated example with the subscription server:
https://github.com/nestjs/nest/tree/master/examples/12-graphql-apollo

Subscribe in one window:

subscription {
  catCreated {
  	name
  }
}

Mutate in the different one:

mutation {
  createCat(name: "Nest") {
    name
  }
}

Everythin works fine 🙂

from graphql.

joefru avatar joefru commented on March 28, 2024

Downloaded the latest example but I still get [object Object] in the results window when I run the subscription query.

Also, what I'd really like to achieve is to have the subscription server listen on the same port as the express http server. That way, I can deploy a single application to Heroku, which only allows a single port per deployment.

from graphql.

kamilmysliwiec avatar kamilmysliwiec commented on March 28, 2024

I have tested this example and it works fine for me, there's no [object Object], that's weird. What kind of mutation are you executing from the graphiql? It has nothing to do with @nestjs/graphql module, but rather with this issue that you mentioned about earlier (apollographql/subscriptions-transport-ws#236 (comment))

from graphql.

Stradivario avatar Stradivario commented on March 28, 2024

@kamilmysliwiec i really don't understand why you delete the comment...

from graphql.

Stradivario avatar Stradivario commented on March 28, 2024

Its a Community right ? and you can share your Subscription Methods to Others ? What is your point ? and problem ?

from graphql.

lock avatar lock commented on March 28, 2024

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

from graphql.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.