Giter Club home page Giter Club logo

graphql's People

Contributors

andreialecu avatar carsonf avatar davide-gheri avatar dependabot[bot] avatar greatsumini avatar greguintow avatar iagomelanias avatar iddan avatar kamilmysliwiec avatar karibash avatar katainaka0503 avatar linus-sh avatar lpessoa avatar luas10c avatar marcus-sa avatar mattleff avatar parkerself22 avatar renovate-bot avatar renovate[bot] avatar roypeled avatar stevefan1999-personal avatar thekip avatar thiagomini avatar thomas-advantitge avatar tony133 avatar toonvanstrijp avatar tugascript avatar tuxmachine avatar vasily-polonsky avatar vinnymac avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

graphql's Issues

POST requests

Hi guys,

I started to use the GraphQL module and I must say that it is awesome. However, I had some difficulties to perform POST requests against my GraphQL endpoints (GET requests works out of the box).

I'm using the following packages:

"dependencies": {
    "@nestjs/common": "^4.5.4",
    "@nestjs/core": "^4.5.4",
    "@nestjs/graphql": "^2.0.0",
    "@nestjs/microservices": "^4.5.3",
    "@nestjs/testing": "^4.5.4",
    "@nestjs/websockets": "^4.5.3",
    ...
    "apollo-server-express": "^1.3.2",
    "graphql": "^0.11.7",
    "graphql-tools": "^2.11.0",
    ...
  }

Here is my GraphQL module implementation, according to the Nestjs documentation:

import {Module, NestModule, MiddlewaresConsumer, RequestMethod} from '@nestjs/common';
import {graphqlExpress, graphiqlExpress} from 'apollo-server-express';
import {GraphQLFactory, GraphQLModule} from '@nestjs/graphql';
import {SnippetResolvers} from "./snippet/snippet.resolvers";
import {SnippetModule} from "../snippet/snippet.module";

@Module({
  imports: [
    GraphQLModule,
    SnippetModule
  ],
  components: [
    SnippetResolvers
  ]
})
export class GQLModule implements NestModule {

  constructor(private readonly graphQLFactory: GraphQLFactory) {}

  configure(consumer: MiddlewaresConsumer) {
    const typeDefs = this.graphQLFactory.mergeTypesByPaths('./**/*.graphql');
    const schema = this.graphQLFactory.createSchema({ typeDefs });
    consumer
      .apply(graphiqlExpress({ endpointURL: '/graphql' }))
      .forRoutes({ path: '/graphiql', method: RequestMethod.GET })
      .apply(graphqlExpress(req => ({ schema, rootValue: req })))
      .forRoutes({ path: '/graphql', method: RequestMethod.ALL });
  }

}

With the following request:

POST /graphql HTTP/1.1
Host: localhost:3000
Content-Type: application/graphql
Cache-Control: no-cache

{ snippets {name}}

I get the following response:

HTTP 500

POST body missing. Did you forget use body-parser middleware?

I found the solution reading some Apollo documentation; all I had to do was to add the following middlewares to my endpoint:

import {Module, NestModule, MiddlewaresConsumer, RequestMethod} from '@nestjs/common';
import {graphqlExpress, graphiqlExpress} from 'apollo-server-express';
import {GraphQLFactory, GraphQLModule} from '@nestjs/graphql';
import {SnippetResolvers} from "./snippet/snippet.resolvers";
import {SnippetModule} from "../snippet/snippet.module";
import * as bodyParser from 'body-parser';

@Module({
  imports: [
    GraphQLModule,
    SnippetModule
  ],
  components: [
    SnippetResolvers
  ]
})
export class GQLModule implements NestModule {

  constructor(private readonly graphQLFactory: GraphQLFactory) {}

  configure(consumer: MiddlewaresConsumer) {
    const typeDefs = this.graphQLFactory.mergeTypesByPaths('./**/*.graphql');
    const schema = this.graphQLFactory.createSchema({ typeDefs });
    consumer
      .apply(bodyParser.text({ type: 'application/graphql' }))
      .forRoutes({ path: '/graphql', method: RequestMethod.ALL })
      .apply((req, res, next) => {
        if (req.is('application/graphql')) {
          req.body = { query: req.body };
        }
        next();
      })
      .forRoutes({ path: '/graphql', method: RequestMethod.ALL })
      .apply(graphiqlExpress({ endpointURL: '/graphql' }))
      .forRoutes({ path: '/graphiql', method: RequestMethod.GET })
      .apply(graphqlExpress(req => ({ schema, rootValue: req })))
      .forRoutes({ path: '/graphql', method: RequestMethod.ALL });
  }

}

At this point, everything looks like working fine for me and I'm pretty happy with this solution. Could any of you give me some impression on this implementation? Is it the way to go? (if yes, then we should maybe add those details to the documentation)

Thanks for your time ๐Ÿ˜„

@Body

Is there any way to add @Body to this library for the args param. Finding it frustrating having to convert POJO's from inputs to TypeScript classes.

Incorrect type for `typeDefs` in GqlModuleOptions

I'm submitting a...


[ x ] Bug report

Current behavior

In the interface GqlModuleOptions, the typeDefs property is inherited from the apollo-server Config interface, which defines it as typeDefs?: DocumentNode | Array<DocumentNode>;

However, when I pass a DocumentNode as the value of typeDefs, I get the following error:

[Nest] 15752   - 2018-9-3 16:43:12   [ExceptionHandler] Syntax Error: Unexpected [ +102ms
Syntax Error: Unexpected [

GraphQL request (5:2)
4: }
5: ,[object Object]
    ^
6:         

    at syntaxError (C:\Development\vendure\vendure\server\node_modules\graphql\error\syntaxError.js:24:10)
    at unexpected (C:\Development\vendure\vendure\server\node_modules\graphql\language\parser.js:1485:33)
    at parseDefinition (C:\Development\vendure\vendure\server\node_modules\graphql\language\parser.js:160:9)
    at parseDocument (C:\Development\vendure\vendure\server\node_modules\graphql\language\parser.js:115:22)
    at parse (C:\Development\vendure\vendure\server\node_modules\graphql\language\parser.js:48:10)
    at parseDocument (C:\Development\vendure\vendure\server\node_modules\graphql-tag\src\index.js:129:16)
    at Object.gql (C:\Development\vendure\vendure\server\node_modules\graphql-tag\src\index.js:170:10)
    at GraphQLFactory.mergeOptions (C:\Development\vendure\vendure\server\node_modules\@nestjs\graphql\dist\graphql.factory.js:32:55)
    at Function.<anonymous> (C:\Development\vendure\vendure\server\node_modules\@nestjs\graphql\dist\graphql.module.js:73:55)
    at Generator.next (<anonymous>)

Passing a string representation of the schema on the other hand works, but then I need to cast the string to any to avoid type errors.

This line in the GraphQLFactory class seems to be the point that the value is used as a string (or array of strings to be exact):

typeDefs: gql`
${options.typeDefs}
`,

Expected behavior

Either the GraphQLFactory should perform a check to see if the typeDefs is a DocumentNode, and if so then skip the gql tag call.

Or just change the GqlModuleOptions to make typeDefs a string type.

Environment


Nest version: 5.3.0, graphql v5.1.0

Custom query resolver is always null

Ho can the query method be passed to the right Query type parent?
Or how can the resolver class be annotated correctly in order to resolve?

.graphql

type CustomQuery{
    foo: String
}
type Query {
    mw: CustomQuery
}

CustomResolver

import { Query, Resolver } from '@nestjs/graphql';

@Resolver()
export class CustomResolver {
  constructor() {}

  @Query()
  foo(): string {
    return 'bar';
  }
}

create schema

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

result

{
  "data": {
    "mw": {
      "foo": null
    }
  },
  "extensions": {
    "tracing": {
      "version": 1,
      "startTime": "2018-02-20T17:01:09.202Z",
      "endTime": "2018-02-20T17:01:09.202Z",
      "duration": 242964,
      "execution": {
        "resolvers": [
          {
            "path": [
              "mw"
            ],
            "parentType": "Query",
            "fieldName": "mw",
            "returnType": "CustomQuery",
            "startOffset": 77828,
            "duration": 96395
          },
          {
            "path": [
              "mw",
              "foo"
            ],
            "parentType": "CustomQuery",
            "fieldName": "foo",
            "returnType": "String",
            "startOffset": 214124,
            "duration": 8691
          }
        ]
      }
    }
  }
}

maybe relevant dependencies

{
  "dependencies": {
    "@nestjs/common": "4.6.4",
    "@nestjs/core": "4.6.4",
    "@nestjs/graphql": "2.0.0",
    "@types/graphql": "0.12.4",
    "graphql": "0.13.1",
    "graphql-tools": "2.21.0"
  } 
}

A) What am I doing wrong?
B) Can anyone confirm that custom query types are not supported at the moment?
C) Would a PR supporting this via annotation be welcomed?

Problem starting a graphql server app implemented via nestjs

Hi,

I followed the instruction to create a nestjs app successfully. I am now trying to add graphql to the server using the instructions provided here https://docs.nestjs.com/graphql/quick-start. After installing the requrired packages via yarn and adding the GraphQLModule with empty schema, i run yarn start and I get the following error:

yarn run v1.7.0
$ ts-node -r tsconfig-paths/register src/main.ts
Error: Cannot find module 'C:\Users\prabakar\Documents\web-server\src/graphql'
at Function.Module._resolveFilename (module.js:547:15)
at Function.Module._resolveFilename (C:\Users\prabakar\Documents\web-server\node_modules\tsconfig-paths\lib\register.js:29:44)
at Function.Module._load (module.js:474:25)
at Module.require (module.js:596:17)
at require (internal/module.js:11:18)
at Object. (C:\Users\prabakar\Documents\web-server\node_modules\apollo-server-core\src\runQuery.ts:1:1)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

I am on windows 10, here is the content of package.json dependencies.

"dependencies": {
"@nestjs/common": "^5.0.0",
"@nestjs/core": "^5.0.0",
"@nestjs/graphql": "^3.0.0",
"@nestjs/microservices": "^5.0.0",
"@nestjs/testing": "^5.0.0",
"@nestjs/typeorm": "^5.0.0",
"@nestjs/websockets": "^5.0.0",
"@types/graphql": "^0.13.1",
"apollo-server-express": "^1.3.6",
"graphql": "^0.13.2",
"graphql-tools": "^3.0.2",
"mysql": "^2.15.0",
"reflect-metadata": "^0.1.12",
"rxjs": "^6.0.0",
"typeorm": "^0.2.7",
"typescript": "^2.8.0"
},

any ideas what is going on?

GraphQL, send array of errors.

Hey, I want know a possibility to send an array of errors using the GraphQL module.

Is it possible with GraphQL module using a mutation? I have no idea how to implement it.

Big thanks.

Subscription on same server throws error. Connection closed before receiving a handshake response.

Trying to configure GraphQL subscriptions using existing express server.

But seems that there is some kind of conflict.
Error thrown in graphiql console:

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

image

When using new server. There is no error.

Here the graphQL configuration I've used:
this.setSameServer() - uses nest http server instance.
this.setDifferentServer() - uses new http instance.

import {
  MiddlewareConsumer,
  Module,
  HttpServer,
  Inject,
  NestModule,
  OnModuleDestroy,
} from '@nestjs/common';
import { AppController } from 'app.controller';
import { AppService } from 'app.service';
import { graphqlExpress, graphiqlExpress } from 'apollo-server-express';
import { GraphQLModule, GraphQLFactory } from '@nestjs/graphql';
import { AuthorResolver } from 'author.resolver';
import { SubscriptionServer } from 'subscriptions-transport-ws';
import { execute, subscribe } from 'graphql';
import { createServer } from 'http';
import { HTTP_SERVER_REF } from '@nestjs/core';

@Module({
  imports: [GraphQLModule, AuthorResolver],
  controllers: [AppController],
  providers: [
    {
      provide: 'SUBSCRIPTION_SERVER',
      useFactory: () => {
        const server = createServer();
        return new Promise(resolve => server.listen(88, () => resolve(server)));
      },
    },
    AppService,
  ],
})
export class AppModule implements NestModule, OnModuleDestroy {
  private subscriptionServer: SubscriptionServer;
  private subscriptionPort: number;
  private wsServer: HttpServer;

  constructor(
    private readonly graphQLFactory: GraphQLFactory,
    @Inject(HTTP_SERVER_REF) private readonly httpServerRef: HttpServer,
    @Inject('SUBSCRIPTION_SERVER') private readonly ws: HttpServer,
  ) {
    this.setSameServer();
    //this.setDifferentServer();
  }

  private setSameServer() {
    this.wsServer = this.httpServerRef.getHttpServer();
    this.subscriptionPort = 3000;
  }

  private setDifferentServer() {
    this.wsServer = this.ws;
    this.subscriptionPort = 88;
  }

  public configure(consumer: MiddlewareConsumer) {
    const typeDefs = this.graphQLFactory.mergeTypesByPaths('./**/*.graphql');
    const schema = this.graphQLFactory.createSchema({ typeDefs });

    const route = '/graphql';
    const routeIDE = '/graphiql';
    const routeSubs = '/subscriptions';

    const middlewareIDE = graphiqlExpress({
      endpointURL: route,
      subscriptionsEndpoint:
        'ws://localhost:' + this.subscriptionPort + routeSubs,
    });
    const middleware = graphqlExpress(req => ({
      schema,
      rootValue: req,
      debug: false,
    }));

    consumer.apply(middleware).forRoutes(route);
    consumer.apply(middlewareIDE).forRoutes(routeIDE);

    this.subscriptionServer = new SubscriptionServer(
      {
        execute,
        subscribe,
        schema,
      },
      {
        server: this.wsServer,
        path: routeSubs,
      },
    );
  }

  public onModuleDestroy() {
    this.subscriptionServer.close();
  }
}

Used these issues for help:
nestjs/nest#500
#6

And full repo if you want to reproduce:
https://github.com/ph55/nest-graphql-subscriptions

Batching and caching

Hi!

I just discovered this framework and I have to say itโ€™s awesome. Kudos!

The GraphQL module is great, but I did not find any information regarding how to do batching and caching, which is pretty required to avoid a big waste of resources (see https://github.com/facebook/dataloader).

Given the fact that resolvers are automatically mapped, I guess thereโ€™s currently no way to do that, right? An integration with dataloader would be awesome, if not mandatory for any medium to large application.

And, happy new year, by the way. โ˜บ๏ธ

Specified query type "Query" not found in document with none graphql file.

When I using the sample/12-graphql-apollo project, and I remove the graphql file, then run this project.

It throws some error:

(node:5278) UnhandledPromiseRejectionWarning: Error: Specified query type "Query" not found in document.
    at /home/dzzzzzy/workspace/nestjs/nest/sample/12-graphql-apollo/node_modules/graphql/utilities/buildASTSchema.js:133:17
    at Array.forEach (<anonymous>)
    at Object.buildASTSchema (/home/dzzzzzy/workspace/nestjs/nest/sample/12-graphql-apollo/node_modules/graphql/utilities/buildASTSchema.js:126:30)
    at buildSchemaFromTypeDefinitions (/home/dzzzzzy/workspace/nestjs/nest/sample/12-graphql-apollo/node_modules/graphql-tools/src/schemaGenerator.ts:225:32)
    at _generateSchema (/home/dzzzzzy/workspace/nestjs/nest/sample/12-graphql-apollo/node_modules/graphql-tools/src/schemaGenerator.ts:92:18)
    at Object.makeExecutableSchema (/home/dzzzzzy/workspace/nestjs/nest/sample/12-graphql-apollo/node_modules/graphql-tools/src/schemaGenerator.ts:120:20)
    at GraphQLFactory.createSchema (/home/dzzzzzy/workspace/nestjs/nest/sample/12-graphql-apollo/node_modules/@nestjs/graphql/dist/graphql.factory.js:23:32)
    at ApplicationModule.createSchema (/home/dzzzzzy/workspace/nestjs/nest/sample/12-graphql-apollo/src/app.module.ts:41:32)
    at ApplicationModule.configure (/home/dzzzzzy/workspace/nestjs/nest/sample/12-graphql-apollo/src/app.module.ts:24:25)
    at MiddlewareModule.loadConfiguration (/home/dzzzzzy/workspace/nestjs/nest/sample/12-graphql-apollo/node_modules/@nestjs/core/middleware/middleware-module.js:35:18)
(node:5278) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 3)
(node:5278) [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 console.log(typeDefs) with none graphql file at other projects, it always throw this error and console shows:

schema {
  query: Query
}

Question: How to get context in @Subscription

I have the following code snippet that works fine in graphql-yoga.

Subscription: {
    post: {
      subscribe: (parent, args, ctx, info) => {
        return ctx.db.subscription.post(
          {
            where: {
              mutation_in: ["CREATED", "UPDATED"]
            }
          },
          info
        );
      }
    }
  },

If I try to get the context in the Nest way - all of those args are undefined

  @Subscription('post')
  onPostMutation(parent, args, ctx, info) {
    // all args are undefined
    // ...
  }

So my question - how to get context and args for a subscription?

GraphQL error handling is incompatible with HttpException and Exception Filters

I'm submitting a...


[ ] Regression 
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

Using Nestjs with the GraphQLModule as documentation describes, there are a problem with throwing HttpException. The error message that GraphQL returns, contains "[Object Object"] in the message field instead the HttpException message.
The GraphQL.js library is expecting an Error instance, but HttpException not inherit from Error. What is the main reason for HttpException is not extending from Error?

In addition to this any Exception Filter is not working.

Expected behavior

Proper error handling and Exception Filters working with GraphQL.

Minimal reproduction of the problem with instructions

Install @nestjs/graphql and configure it as documentation describes. In any resolver try to throw a HttpException (or a inherited custom one). GraphQL returns an error like this:

{
  "data": {
    "findOneUserById": null
  },
  "errors": [
    {
      "message": "[object Object]",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "findOneUserById"
      ]
    }
  ]
}

What is the motivation / use case for changing the behavior?

Proper error handling working with GraphQL and documentation for how to deal with this.

Environment


- "@nestjs/common": "^4.5.9",
-  "@nestjs/core": "^4.5.10",
-  "@nestjs/graphql": "^2.0.0",
-  "@nestjs/microservices": "^4.5.8",
-  "@nestjs/testing": "^4.5.5",
-  "@nestjs/websockets": "^4.5.8",

 
For Tooling issues:
- Node version: 9.4.0  
- Platform:  Linux 

Others:

- Kubuntu
- WebStorm
- GraphiQL
- npm

Subscription endpoint is not defined

I'm submitting a...


[ ] Regression 
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

{
  "error": "Could not connect to websocket endpoint ws://localhost:3000/graphql. Please check if the endpoint url is correct."
}

Expected behavior

It should subscribe to changes.

Minimal reproduction of the problem with instructions

Checkout https://github.com/nestjs/nest/tree/master/sample/12-graphql-apollo
Fire subscription query

subscription {catCreated {id name}}

What is the motivation / use case for changing the behavior?

Well its a bug - so ^^

Environment


Nest version: latest

 
For Tooling issues:
- Node version: 9  
- Platform Mac

Support premade schema

I'm submitting a...


[ ] Regression 
[ ] Bug report
[x] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

typePaths is mandatory and dominant, without it on graphql.mergeTypes it will throw an error.

Expected behavior

I should be able to use a pre-cooked schema out of the box.

Minimal reproduction of the problem with instructions

    GraphQLModule.forRootAsync({
      imports: [
        TypeGQLModule.forSchema({
          resolvers: [
            DefaultResolver,
            ...ModuleLocator.flattenModuleField('resolvers')
          ],
          pubSub,
          authChecker
        })
      ],
      async useFactory(graphQL: GraphQlBridge): Promise<GqlModuleOptions> {
        const schema: GraphQLSchema = graphQL.buildSchema()

        const playground: any = {
          settings: {
            'editor.cursorShape': 'line'
          }
        }

        return {
          schema,
          introspection: true,
          tracing: true,
          context: ({ req, res }) => ({
            req,
            res
          }),
          playground
        }
      },
      inject: [GraphQlBridge]
    })
  ],

It failed with:

Error: Specified query type "Query" not found in document.
    at E:\typescript-starter\node_modules\graphql\utilities\buildASTSchema.js:184:15
    at Array.forEach (<anonymous>)
    at getOperationTypes (E:\typescript-starter\node_modules\graphql\utilities\buildASTSchema.js:177:27)
    at Object.buildASTSchema (E:\typescript-starter\node_modules\graphql\utilities\buildASTSchema.js:127:36)
    at Object.buildSchemaFromTypeDefinitions (E:\typescript-starter\node_modules\graphql-tools\dist\generate\buildSchemaFromTypeDefinitions.js:24:28)
    at Object.makeExecutableSchema (E:\typescript-starter\node_modules\graphql-tools\dist\makeExecutableSchema.js:27:29)
    at GraphQLFactory.mergeOptions (E:\typescript-starter\node_modules\@nestjs\graphql\dist\graphql.factory.js:30:98)
    at Function.<anonymous> (E:\typescript-starter\node_modules\@nestjs\graphql\dist\graphql.module.js:73:55)
    at Generator.next (<anonymous>)
    at E:\typescript-starter\node_modules\@nestjs\graphql\dist\graphql.module.js:19:71
    at new Promise (<anonymous>)
    at __awaiter (E:\typescript-starter\node_modules\@nestjs\graphql\dist\graphql.module.js:15:12)
    at Object.useFactory [as metatype] (E:\typescript-starter\node_modules\@nestjs\graphql\dist\graphql.module.js:71:68)
    at resolveConstructorParams (E:\typescript-starter\node_modules\@nestjs\core\injector\injector.js:68:55)
    at Injector.resolveConstructorParams (E:\typescript-starter\node_modules\@nestjs\core\injector\injector.js:99:30)
    at process._tickCallback (internal/process/next_tick.js:68:7)

What is the motivation / use case for changing the behavior?

I used MagnusCloudCorp/nestjs-type-graphql instead of the helpers from @nestjs/graphql provided out of the box and TypeGraphQL provided a compiled schema instead of SDL.

Environment


Nest version: 5.1.0

Extra info

This is the reason it failed:

mergeOptions(options: GqlModuleOptions = { typeDefs: [] }): GqlModuleOptions {
const resolvers = extend(
this.scalarsExplorerService.explore(),
this.resolversExplorerService.explore(),
);
return {
...options,
typeDefs: undefined,
schema: makeExecutableSchema({
resolvers: extend(resolvers, options.resolvers),
typeDefs: gql`
${options.typeDefs}
`,
}),
};
}

My schema option, no matter what are always gonna be Object.assign'd

DeprecationWarning: Unhandled promise rejections when mergeTypesByPaths or createSchema

Hi,

I have an issue, when merge types and create schema, on terminal console show errors like this:

node:8726) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): TypeError: buildASTSchema.getDescription is not a function
(node:8726) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled willterminate the Node.js process with a non-zero exit code.

this is my code

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

consumer
      .apply(graphqlExpress(req => ({ schema: {}, rootValue: req })))
      .forRoutes({ path: '/graphql', method: RequestMethod.ALL });

Support GraphQL resolvers that returns observables

Hi, I am new to NestJS, so I hope this issue is not my mistake. I think NestJS's GraphQL module does not support resolvers that returns observables. This is kind of unexpected as the REST counterpart (i.e. controllers) supports observables.

With heyPromise, I am able to get 'from promise'. However, heyObservable returns this instead:

{
  "data": {
    "heyObservable": "[object Object]"
  }
}

The expected data for heyObservable should be 'from rxjs'. For now, we will need to workaround by turning the observable into a promise (i.e. heyObservable_workaround_is_ok)

Snippet of schema & resolvers used:

type Query {
    heyPromise: String
    heyObservable: String
}

  @Query()
  async heyPromise () {
    return new Promise(resolve => resolve('from promise'))
  }

  @Query()
  heyObservable () {
    return of('from rxjs')
  }

  @Query()
  heyObservable_workaround_is_ok () {
    return of('from rxjs').toPromise()
  }

`GraphQLFactory.mergeTypesByPaths` not working with multiple patterns

Following code

    const typeDefs = this.graphQLFactory.mergeTypesByPaths(
      `src/@core/**/*.graphqls`,
      `src/${process.env.APP_NAME}/**/*.graphqls`
    );

will only generate type definitions for first pattern: src/@core/**/*.graphqls, all next patterns not merged.

Manual merging fixes this issue:

    import { fileLoader, mergeTypes } from 'merge-graphql-schemas';

    const coreTypes = fileLoader(`src/@core/**/*.graphqls`);
    const appTypes = fileLoader(`src/${process.env.APP_NAME}/**/*.graphqls`);

    const types = coreTypes.concat(appTypes);

    const typeDefs = mergeTypes(types);

Add a @DirectiveResolver decorator

Currently, NestJS doesn't support GraphQL directives at all, since the directiveResolvers in makeExecutableSchema is missing https://github.com/nestjs/graphql/blob/master/lib/graphql.factory.ts#L28

I wanted to use directives in my model (for authentication etc) and I bumped into #17 but I realized it's not just the mapping to Guards, but that NestJS is totally missing directives.

PS: An example of how to use Directives https://codeburst.io/use-custom-directives-to-protect-your-graphql-apis-a78cbbe17355 and how graphql-tools implements it here https://github.com/apollographql/graphql-tools/blob/master/docs/source/directive-resolvers.md#directive-example

Apollo Server own middleware

Since apollo-server-express is not working in the Nest way, a new middleware, that adapts to the Exception handling of Nest should be created. The original issue was created in @nestjs/nest since the example in the documentation leads to use this library.

Related issue nestjs/nest#556

Use pre-defined schema?

Hallo,

in a previous release there has been the GraphQLFactory provider with the createSchema()-function. This has been removed and it seems there is no way to pass merged GraphQL types to GraphQLModule.forRoot(). Am I right or did I overlook something?

What is the reason to remove support for predefined types?

My use case is this: I have a multi-repo project and one of them returns the merged types. Until now I have simply passed them to createSchema(), but now I have to update to the latest nestjs/graphql version (I need the Root()-decorator).

Thanks,
Steven

Support of multiple endpoints

I'm submitting a...

[ ] Regression 
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

I want to implement two endpoints. For this goal I have two modules: AdminModule and SiteModule. In each module I imported GraphQLModule:

GraphQLModule.forRootAsync({
  useFactory: async () => {
    return {
      typePaths: ['./src/admin/**/*.graphql'],
      path: '/admin',
    }
  },
})

and

GraphQLModule.forRootAsync({
  useFactory: async () => {
    return {
      typePaths: ['./src/site/**/*.graphql'],
      path: '/site',
    }
  },
})

In this case only /admin is available. When I request /site it returns 404. From another side I can use forRoot instead of forFootAsync. In this case both endpoints work as expected. But I have to use forRootAsync for have possibility to define allowResolversNotInSchema: true by the issue described in #19. Without It I get error: Error: "Mutation" defined in resolvers, but not in schema when in shared module I add some resolver which defined only in one of two schemes.

Expected behavior

Possibility for implement multiple endpoints

Minimal reproduction of the problem with instructions

  1. Use with example https://github.com/nestjs/nest/tree/master/sample/12-graphql-apollo/src
  2. Add two modules with configs as described above.

What is the motivation / use case for changing the behavior?

It is very convenient for have possibility for split public and protected API.

Environment

Nest version: 5.3.0
 
For Tooling issues:
- Node version: 10.1.0
- Platform:  Windows

Schema validation

Hello,

Is there any good way to validate data in mutations like string length etc?

typescript mutation { createSth(name:"something", website:"http://test.com/") { id name website } }

How can i validate name or website data?

PS: Kamil, great job with nestjs!

Regards

Example not working for me

I have following code:

import {
  Module,
  MiddlewaresConsumer,
  NestModule,
  RequestMethod,
} from '@nestjs/common';
import { graphqlExpress } from 'apollo-server-express';
import { GraphQLModule, GraphQLFactory } from '@nestjs/graphql';
import {UsersModule} from './Users/users.module';

@Module({
  imports: [GraphQLModule],
  modules: [UsersModule],
export class ApplicationModule {
  constructor(private readonly graphQLFactory: GraphQLFactory) {}
}

And application exits with following error:

[Nest] 24011   - 2018-2-13 13:06:05   [NestFactory] Starting Nest application...
[Nest] 24011   - 2018-2-13 13:06:05   [ExceptionHandler] Nest can't resolve dependencies of the ApplicationModule (?). Please verify whether [0] argument is available in the current context.
Error: Nest can't resolve dependencies of the ApplicationModule (?). Please verify whether [0] argument is available in the current context.
    at Injector.<anonymous> (/home/tymur/Learning/nest/project/node_modules/@nestjs/core/injector/injector.js:160:23)
    at Generator.next (<anonymous>)
    at fulfilled (/home/tymur/Learning/nest/project/node_modules/@nestjs/core/injector/injector.js:4:58)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:160:7)
    at Function.Module.runMain (module.js:703:11)
    at startup (bootstrap_node.js:190:16)
    at bootstrap_node.js:662:3
 1: node::Abort() [node]
 2: 0x8c8099 [node]
 3: v8::internal::FunctionCallbackArguments::Call(void (*)(v8::FunctionCallbackInfo<v8::Value> const&)) [node]
 4: 0xaddc5c [node]
 5: v8::internal::Builtin_HandleApiCall(int, v8::internal::Object**, v8::internal::Isolate*) [node]
 6: 0x3ab9ebd042fd
Aborted (core dumped)

UsersModule is dummy module:

import {Module} from '@nestjs/common';
import {UsersService} from './users.service';
import UsersController from './users.controller';
import {usersProviders} from './users.providers';
import {DatabaseModule} from '../common/database/database.module';
import {LibrariesModule} from '../Libraries/libraries.module';
import {UserResolver} from './user.resolver';

@Module({
  // modules: [DatabaseModule, LibrariesModule],
  // controllers: [UsersController],
  // components: [
  //   UsersService,
  //   ...usersProviders,
  //   UsersResolver,
  // ],
  // exports: [
  //   UsersService,
  // ],
})
export class UsersModule {}

but if i comment out modules: [UsersModule], in ApplicationModule, everithing works fine. Same as commenting out constructor in application module. What im doing wrong?

TypeError: Cannot convert undefined or null to object

I have seen those similar issues nestjs/nest#484, nestjs/nest#488 and they seem to be resolved. However, I am on @nestjs/graphql v3.0.0, @nestjs/common and /core v5.0.0 and the following code:

@Module({
	imports: [GraphQLModule]
})
export class GraphQLSetupModule {
	private readonly schema: any;

	constructor(graphQLFactory: GraphQLFactory) {
		this.schema = graphQLFactory.createSchema({
			typeDefs: mergedTypes
		});
	}
}

where mergedTypes is exactly:

schema {
  query: Query
}

type Query {
  countries: [Country]
}

directive @entity on OBJECT

type Country @entity {
  # The id is also the official ISO code of the country.
  _id: ID
  name: String
}

fails with stack trace:

TypeError: Cannot convert undefined or null to object
    at Function.getPrototypeOf (<anonymous>)
    at ResolversExplorerService.filterResolvers (/Users/danielkucal/Applications/someApp/src/node_modules/@nestjs/graphql/dist/resolvers-explorer.service.js:34:34)
    at resolvers.flatMap.instance (/Users/danielkucal/Applications/someApp/src/node_modules/@nestjs/graphql/dist/resolvers-explorer.service.js:27:66)
    at map (/Users/danielkucal/Applications/someApp/src/node_modules/@nestjs/graphql/dist/resolvers-explorer.service.js:31:102)
    at Array.map (<anonymous>)
    at lodash_1.flattenDeep.modules.map.module (/Users/danielkucal/Applications/someApp/src/node_modules/@nestjs/graphql/dist/resolvers-explorer.service.js:31:80)
    at Array.map (<anonymous>)
    at ResolversExplorerService.flatMap (/Users/danielkucal/Applications/someApp/src/node_modules/@nestjs/graphql/dist/resolvers-explorer.service.js:31:45)
    at ResolversExplorerService.explore (/Users/danielkucal/Applications/someApp/src/node_modules/@nestjs/graphql/dist/resolvers-explorer.service.js:27:32)
    at GraphQLFactory.createSchema (/Users/danielkucal/Applications/someApp/src/node_modules/@nestjs/graphql/dist/graphql.factory.js:23:149)
    at new GraphQLSetupModule (/Users/danielkucal/Applications/someApp/src/LHBackend/dist/src/graphql/GraphQLSetupModule.js:27:38)
    at resolveConstructorParams (/Users/danielkucal/Applications/someApp/src/node_modules/@nestjs/core/injector/injector.js:64:84)
    at Injector.resolveConstructorParams (/Users/danielkucal/Applications/someApp/src/node_modules/@nestjs/core/injector/injector.js:86:30)
    at process._tickCallback (internal/process/next_tick.js:178:7)

Any ideas? Thanks in advance!

Guards not working as they should

I found an issue regarding guards. Let's take the following example:

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
import { Reflector } from '@nestjs/core';

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private readonly reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const roles = this.reflector.get<string[]>('roles', context.getHandler());
    if (!roles) {
      return true;
    }
    const request = context.switchToHttp().getRequest();
    const user = request.user;
    return user && user.role && roles.some((role) => role === user.role));
  }
}

Now, in the rest of the framework this works like a charm. But whenever you are in graphql, this doesn't work quite as well. Taking the following .gql file.

type Bookings implements Node {
   id: ID!
   ...
}

type BookingEdge {
  cursor: ID!
  node: Booking
}

type BookingConnection {
  edges: [BookingEdge]
  nodes: [Booking]
  pageInfo: PageInfo!
  totalCount: Int!
}

type Restaurant implements Node {
   id: ID!
   orders(first: Int, after: String, last: Int, before: String):OrderConnection
   ...
}

type Query {
   restaurant(id: ID!): Restaurant
}

For the following query, the const request = context.switchToHttp().getRequest(); becomes the user.

query ($id: ID!) {
	restaurant(id: $id) {
			id
			bookings {
				nodes {
					id
				}
			}
		}
}

So, in this query, request.user in the guard, becomes undefined and you have to make a workaround:

canActivate(context: ExecutionContext): boolean | Promise<boolean> {
    const roles = this.reflector.get<string[]>('roles', context.getHandler());
    const request = context.switchToHttp().getRequest(); //this works only for when querying a parent type
    const ctx = context.getArgByIndex(2); // this works for when querying a child.
    const user = request.user ||ย ctx.user;
    return user && user.role && roles.some((role) => role === user.role));
}

Can you guys check if it happens to you or it's an issue of mine? Thank you.

Cannot inject GraphQLFactory into forRootAsync factory/class

I'm submitting a...


[ x ] Bug report

Current behavior

When I try to inject GraphQLFactory into either a factory function or a class passed to GraphQLModule.forRootAsync(), the app fails to bootstrap, with no error displayed in the console.

Expected behavior

I think I should be able to inject GraphQLFactory and use it in a factory or class passed to .forRootAsync().

Minimal reproduction of the problem with instructions

  1. git clone [email protected]:nestjs/nest.git
  2. cd nest/sample/12-graphql-apollo
  3. npm install
  4. edit app.module.ts to look like:
imports: [
    CatsModule,
    GraphQLModule.forRootAsync({
      useFactory(graphQLFactory: GraphQLFactory) {
        return {
          typePaths: ['./**/*.graphql'],
          installSubscriptionHandlers: true,
        };
      },
      inject: [GraphQLFactory]
    }),
  ],
  1. npm run start

What is the motivation / use case for changing the behavior?

I want to use the GraphQLFactory.mergeTypesByPaths() method to do some pre-processing of my schema when bootstrapping my app. Up until today I was using the old v3.0.0 way of configuring graphql, where I could inject GraphQLFactory into my AppModule.

Now I am upgrading to v5.1.0 and it seems that when I try to inject GraphQLFactory into either a factory function or a class passed to GraphQLModule.forRootAsync(), the app fails to bootstrap with no error.

Environment


Nest version: 5.3.0

"@nestjs/common": "^5.3.0",
"@nestjs/core": "^5.3.0",
"@nestjs/graphql": "^5.1.0",

Support AuthGuard

I'm submitting a...


[X] Regression 
[X] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

I can't access the request within my guards anymore. The request within the execution context is always undefined. It looks like the request doesn't get passed through apollo server correctly.

Expected behavior

The request should be accessible within guards.

Minimal reproduction of the problem with instructions

https://github.com/w0wka91/nest/tree/graphql-passport-integration

What is the motivation / use case for changing the behavior?

The request should be accessible to authenticate the user. Furthermore this behavior doesn't let me integrate nestjs/passport into my application.

Environment


Nest version: 5.3.0

 This error accurs since apollo server was updated
For Tooling issues:
- Node version: 10.9  
- Platform:  Mac 

Others:

Multiple guards

If the parent resolver and the child resolver both have Guard, the validate function of the guard will be triggered twice. The guard of parent will be passed with the request object, while the guard of the child will be passed with whatever parent resolver returns.

@Resolver('User')
export class UserResolvers {
    constructor(
        private readonly userService: UserService
    ) {}

    @UseGuards(CustomGuard) // validate function here will get request object
    @Query('me')
    async getUser(obj, args, context, info) {
        const { user } = context
        return {
            account_type: user.accountType,
            balance: user.balance,
            currency: user.currency,
            id: user.accountId
        }
    }

    @UseGuards(CustomGuard)  // validate function here will get the result of getUser
    @ResolveProperty('balance') 
    async getBalance(obj, args, context, info) {
        if (obj.balance) return obj.balance
        const data = await this.userService.getAccount(context, context.user.session)
        return data.balance
    }
}

Header decorator for resolvers

I'm submitting a...


[ ] Regression 
[ ] Bug report
[x] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

I cant't figure out how set custom header during a query request.
Header decorator, doesn't work, nor Response decorator.
Let me know if there is another way.

Expected behavior

There should be the ability to use header decorator as for the controller:
@Header('x-custom-header', 'xxxx')
@query('books')
async getBooks() {
....
}

Minimal reproduction of the problem with instructions

What is the motivation / use case for changing the behavior?

Environment


Nest version: X.Y.Z

 
For Tooling issues:
- Node version: XX  
- Platform:  

Others:

Apollo Server 2.0

Does this package support Apollo Server 2.0 or the older version? I installed their release candidate for express (apollo-server-express@rc). graphqlExpress is no longer available. import { graphqlExpress } from 'apollo-server-express'; How would I go about using nestjs/graphql with Apollo Server 2.0?

thank you

Extending resolvers in `createSchema` not working

This syntax is not working in the NPM version. Probably a release is pending.

const resolvers = {
  UUID: GraphQLUUID
}

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

Why all methods in class with @Resolver are resolvers

Example:
`import { Query, Resolver } from '@nestjs/graphql';

@resolver('Example')
export class ExampleResolvers {
constructor() {
}
@query('example')
async example(obj, args, context, info) {
return {name: 'alik'};
}
async otherMethod() {
return 'hello word';
}
}
`

y have this error (node:8600) UnhandledPromiseRejectionWarning: Error: Example.otherMethod defined in resolvers, but not in schema

union/interface type resolution not working/missing

I'm submitting a...Bug report


[ ] Regression 
[*] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
 

Current behavior

Hello,
I'm using the graphql example( in the example directory of nest) with the Cat CRUD and i try to use a union type and interface but i didn't find a way to do it.
When i try to request my data with a fragment, i have the following error :

"Abstract type MutationResult must resolve to an Object type at runtime for field Mutation.createCat with value "[object Object]", received "undefined". Either the MutationResult type should provide a "resolveType" function or each possible types should provide an "isTypeOf" function."

There is nothing in the doc explaining how to use union / interface, and there is nothing in the graphql example.

In the apollo documentation, the type resolver ( here "Cat" Resolver") should implement a __resolveType function. I tried to set this function in the @resolver('Cat') class CatsResolvers
but it's not working.

I tried to add it on the cat resolvers class

Expected behavior

The request should return either a Cat item or GraphQLErrorItem from my schema definition.

Minimal reproduction of the problem with instructions


export interface GraphQLError {
    readonly message: string;
    readonly errorCode: number;
    readonly type: string;
}
 
  • add type and union

type GraphQLError {
    message: String
    errorCode: Int
    type: String
}
union MutationResult = Cat | GraphQLError
 
  • change the createCat Mutation in the schema

- createCat(name: String, age: Int): MutationResult
 
  • add the function in cats.resolvers.ts in the CatsResolvers class

__resolveType(obj, context, info): string{
    return obj.errorCode ? 'GraphQLError' : 'Cat';
  }
 

What is the motivation / use case for changing the behavior?

Environment


Nest version: 4.5.10 (core)

 
For Tooling issues:
- Node version: 9.4
- Platform:  Mac

Others:

 

How Directive Resolvers are Matched with Guards/Interceptors

Here is a good example on how to apply Auth in GraphQL using Directive Resolvers as "resolvers middlewares" -> https://blog.graph.cool/graphql-directive-permissions-authorization-made-easy-54c076b5368e. Currently this module don't support to define directives, even that graphql-tools allows it.

I don't know how that is handled in combination with Guards/Interceptors of Nest. Using this kind of directives allow the Schema definition to be discovered by the users and depending the role to show or hide specific fields.

v5.0 is missing

@nestjs/graphql v5.0.0 not published?

When I run the nest sample 12-graphql-apollo, it throws some errors

TSError: โจฏ Unable to compile TypeScript:
src/app.module.ts(8,19): error TS2339: Property 'forRoot' does not exist on type 'typeof GraphQLModule'.

Impossible to fetch the context from the graphQLOptions in the resolver

Playing with the graphql sample provided in the samples of nestjs, I was looking for a way to fetch the context in the resolver in order to extract user token in the header of the request to forward it to other backend services.
Unfortunately, it does not seem to be given as parameter despite its presence in the method signature -> findByOneId.

Here follows the context added to each request and expected in the resolver method call (object ->req.headers)...

  configure(consumer: MiddlewareConsumer) {
    const schema = this.createSchema();
    this.subscriptionsService.createSubscriptionServer(schema);

    consumer
      .apply(
        graphiqlExpress({
          endpointURL: '/graphql',
          subscriptionsEndpoint: `ws://localhost:3001/subscriptions`,
        }),
      )
      .forRoutes('/graphiql')
      .apply(graphqlExpress(req => ({ schema, rootValue: req, context: req.headers })))
      .forRoutes('/graphql');
  }
  @Query('cat')
  async findOneById(obj, args, context, info): Promise<Cat> {
    const { id } = args;
    return await this.catsService.findOneById(+id);
  }

All parameters are undefined except the args one which contains the id.

Moreover, I figured out other unexpected behaviors when adding decorators to the method:

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

Here all arguments are undefined except the args one which contains... the context !! (same issue when replacing the @Req() with @Body())

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

2 decorators allows here to fetch the whole GraphQLOptions in the args parameter (other param still undefined). Same behavior for the signature async findOneById(args): Promise<Cat>.

Define resolver for Custom scalar type

I'm trying to migrate my old nestjs app with graphQL to new GraphqlModule. And i faced with problem how to define resolver for scalar type, previously i had:

scalar Date

type User {
  _id: ID!
  fullName: String
  email: String
  hireDate: Date
  pictureUrl: String
}
import { GraphQLScalarType } from 'graphql';
import { Kind } from 'graphql/language';

export const resolver = {
  Date: new GraphQLScalarType({
    name: 'Date',
    description: 'Date custom scalar type',
    parseValue(value) {
      return new Date(value); // value from the client
    },
    serialize(value) {
      return value.getTime(); // value sent to the client
    },
    parseLiteral(ast) {
      if (ast.kind === Kind.INT) {
        return parseInt(ast.value, 10); // ast value is always in string format
      }

      return null;
    }
  })
};

So how do i define resolver for Date type using nestjs annotations ?
I've tried this but it doesn't work

@Resolver('Date')
export class DateResolver {

  @DelegateProperty('Date')
  getDate() {
    return new GraphQLScalarType({
      name: 'Date',
      description: 'Date custom scalar type',
      parseValue(value) {
        return new Date(value); // value from the client
      },
      serialize(value) {
        return value.getTime(); // value sent to the client
      },
      parseLiteral(ast) {
        if (ast.kind === Kind.INT) {
          return parseInt(ast.value, 10);
        }

        return null;
      }
    });
  }
}

inject @Req / context / info to @ResolveProperty()

In @query, we get the parameters (args, context, info) like this

@Query()
user(_, args, context, info) {

And req can be retrieved from context or info

Is it possible to get the req from @ResolveProperty too? I have tried something like this but it does not work.

@ResolveProperty()
userExperience(user: user, @Req() request) {

Scalar types

I have a question; I have the following scheme:

scalar qq

type Liquid {
nliquid: Int
fecha: qq
}

type Query {
liquidaciones: [Liquid]
}
why when sending the query

{
liquidaciones{
nliquid
fecha
}
}
get the next result

{
"data": {
"liquidaciones": [
{
"nliquid": 1,
"fecha": "2004-11-16T03:00:00.000Z",
},
{
"nliquid": 2,
"fecha": "2004-12-13T03:00:00.000Z",
"descrip": "NOVIEMBRE 2004"
}
}

without having defined the scalar qq, even changing qq for any other text (other than Int, String, Float or ID)

Incorrect schema merging when using typeDefs rather than typePaths

I'm submitting a...


[ x ] Bug report

Current behavior

(Me again! Thanks for the incredibly rapid response to my last two issues - hopefully this is the last for a while ... ๐Ÿ˜„ )

So in my app I am using the typeDefs config option and omitting typePaths because I do some of my own pre-processing of the schema files before handing them off to Nest.

There is an issue currently with this part of the GraphQLModule code:

const typeDefs = this.graphQLFactory.mergeTypesByPaths(
...(this.options.typePaths || []),
);
const apolloOptions = await this.graphQLFactory.mergeOptions({
...this.options,
typeDefs: extend(typeDefs, this.options.typeDefs),
});

When this.options.typePaths is falsy (undefined in my case), then the call to this.graphQLFactory.mergeTypesByPath() will return the following string:

schema {
  query: Query
}

When this is later combined with the string I pass as the typeDefs value, then the resulting schema only contains my Queries, but none of my Mutations.

Expected behavior

Passing typeDefs and no typePaths should result in a schema exactly equivalent to that defined by the typeDefs string.

Minimal reproduction of the problem with instructions

  1. git clone [email protected]:nestjs/nest.git
  2. cd nest/sample/12-graphql-apollo
  3. npm install
  4. edit app.module.ts to look like:
   GraphQLModule.forRootAsync({
      useFactory() {
        return {
          installSubscriptionHandlers: true,
          typeDefs: `
          type Query {
            getCats: [Cat]
            cat(id: ID!): Cat
          }
          
          type Mutation {
            createCat(name: String): Cat
          }
          
          type Subscription {
            catCreated: Cat
          }
          
          type Cat {
            id: Int
            name: String
            age: Int
          }
          `
        };
      },
    }),
  1. npm run start

When trying to execute the createCat mutation, you will not get the error: "Schema is not configured for mutations."

Additional note: I noticed when putting together the reproduction that when passing the above config to the .forRoot() method, the app does not even bootstrap, instead failing with the error:

UnhandledPromiseRejectionWarning: Error: Type "Query" was defined more than once.
    at Object.buildASTSchema (C:\Development\temp\nest\sample\12-graphql-apollo\node_modules\graphql\utilities

What is the motivation / use case for changing the behavior?

Sometimes you need to pre-process the typedefs before handing off to Nest. In my case, I use user config to create custom fields at run-time.

Suggested fix

I fixed the issue locally by changing line 100 to:

const typeDefs = this.options.typePaths ? this.graphQLFactory.mergeTypesByPaths(
      ...(this.options.typePaths || []),
    ) : '';

Environment


Nest version: 5.3.2, graphql v5.1.1

Support RxJS

It is possible to provide RXJS support for resolver functions (@Query(), @Mutation(), @ResolveProperty(), ...) ? Like nest route handler, they could return RXJS observable streams :

@Query()
findAll(): Observable<any[]> {
  return of([]);
}

Subscriptions client examples?

Very excited about NestJS. Thinking of becoming a sponsor if it proves out for my new project.

I need to get GraphQL subscriptions working. For starters, I've implemented the example from docs, and now I'm trying to connect GraphiQL with something like this:

  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});

I'm getting ERR_CONNECTION_REFUSED in browser console. I feel like I'm missing the connection between GraphQL Subscriptions and WebSockets, but I can't seem to piece it together from the docs.

Are there any working e2e examples out there?

Bug: Cannot set headers after they are sent to the client

I'm submitting a...


[ ] Regression 
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

import graphqlPlayground from 'graphql-playground-middleware-express';

// ...
 consumer
      .apply(
        // Here the error happens
        graphqlPlayground({
          endpoint: '/graphql',
          subscriptionsEndpoint: `ws://localhost:5001/subscriptions`
        })
      )
      .forRoutes('/graphiql')
      .apply(
        graphqlExpress(async req => ({
          schema,
          rootValue: req,
          context: req,
          formatError: (error: GraphQLError) => {
            return error.originalError instanceof BaseException ? error.originalError.serialize() : error;
          }
        }))
      )
      .forRoutes('/graphql');
(node:10937) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:471:11)
    at ServerResponse.header (/Users/cschroeter/Workspace/Playground/graphql-yoga/nest-yoga/node_modules/express/lib/response.js:767:10)
    at ServerResponse.send (/Users/cschroeter/Workspace/Playground/graphql-yoga/nest-yoga/node_modules/express/lib/response.js:170:12)
    at ServerResponse.json (/Users/cschroeter/Workspace/Playground/graphql-yoga/nest-yoga/node_modules/express/lib/response.js:267:15)
    at ExpressAdapter.reply (/Users/cschroeter/Workspace/Playground/graphql-yoga/nest-yoga/node_modules/@nestjs/core/adapters/express-adapter.js:41:52)
    at ExceptionsHandler.next (/Users/cschroeter/Workspace/Playground/graphql-yoga/nest-yoga/node_modules/@nestjs/core/exceptions/exceptions-handler.js:33:29)
    at /Users/cschroeter/Workspace/Playground/graphql-yoga/nest-yoga/node_modules/@nestjs/core/router/router-proxy.js:12:35
    at Layer.handle [as handle_request] (/Users/cschroeter/Workspace/Playground/graphql-yoga/nest-yoga/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/Users/cschroeter/Workspace/Playground/graphql-yoga/nest-yoga/node_modules/express/lib/router/index.js:317:13)
    at /Users/cschroeter/Workspace/Playground/graphql-yoga/nest-yoga/node_modules/express/lib/router/index.js:284:7

Expected behavior

Instead of the classic GraphiQL UI, I would like to use the superior graphql-playground-middleware-express

Environment


"@nestjs/common": "5.0.1",
"@nestjs/core": "5.0.1",
"@nestjs/graphql": "3.0.0",
"@nestjs/mongoose": "5.0.0",
"@nestjs/passport": "1.0.10",
"@nestjs/testing": "5.0.1"

 
For Tooling issues:
- Node version: 10.2.1
- Platform:  Mac OS

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.