maticzav / graphql-shield

πŸ›‘ A GraphQL tool to ease the creation of permission layer.
https://graphql-shield.com
MIT License
3.55k stars 172 forks source link

Types of property 'middlewares' are incompatible. #151

Closed artemzakharov closed 5 years ago

artemzakharov commented 6 years ago

Bug report

Describe the bug

When using the most current versions of the graphql-yoga and graphl-shield libraries, trying to add shield({ ... }) to the middlewares option of the server creates this error:

image

(it keeps going for quite a while, just didn't want to copy and paste five dozen lines)

To Reproduce

Copy and paste the Graphql Yoga example file. No changes are necessary for the error to pop up.

Additional context

graphql-yoga version: 1.16.2 graphql-shield version: 3.2.2

JazminElkan-Gonzalez commented 6 years ago

same issue, looks like "shield" type has changed from IMiddleware to IMiddlewareGenerator. specifically it went from (in 2.2.7)

export declare function shield(ruleTree?: IRules, _options?: IOptions): IMiddleware;

to (in 3.2.2)

export declare function shield<TSource = any, TContext = any, TArgs = any>(ruleTree: IRules, options?: IOptionsConstructor): IMiddlewareGenerator<TSource, TContext, TArgs>;

maticzav commented 6 years ago

Hey @artemzakharov @JazminGonzalez-Rivero πŸ‘‹,

I tried to reproduce the error but had no luck. I used typescript-advanced boilerplate and then installed graphql-shield as a dependency. Here are my commands;

graphql create sample
cd sample
yarn add graphql-shield

and code;

import {GraphQLServer} from 'graphql-yoga'
import {shield, allow} from 'graphql-shield'
import {Prisma} from './generated/prisma'
import resolvers from './resolvers'

const server = new GraphQLServer({
  typeDefs: './src/schema.graphql',
  resolvers,
  middlewares: [
    shield({
      Query: allow,
    }),
  ],
  context: req => ({
    ...req,
    db: new Prisma({
      endpoint: process.env.PRISMA_ENDPOINT, // the endpoint of the Prisma API (value set in `.env`)
      debug: true, // log all GraphQL queries & mutations sent to the Prisma API
      // secret: process.env.PRISMA_SECRET, // only needed if specified in `database/prisma.yml` (value set in `.env`)
    }),
  }),
})
server.start(() => console.log(`Server is running on http://localhost:4000`))

Super barebones. Since I wasn't able to reproduce the bug, I suggest you try removing node_moudles and reinstall everything. Did you by chance add graphql-middleware as a project dependency? I know this has caused compatibility errors as graphql-yoga already ships with graphql-middleware.

Let me add a quick note about the versioning; I assume you are both familiar with semantic-versioning; majors indicate backward incompatibility (X.x.x), minors indicate new features (x.X.x) and fixes are just fixes (x.x.X). So, the latest version of graphql-shield shipped with incompatible backward types - IMiddleware was changed to IMiddlewareGenerator, that's why there's also a major version bump to indicate this particular change.

I hope this clears things out a bit. Let me know if you're still experiencing the problem. πŸ™‚

JazminElkan-Gonzalez commented 6 years ago

@maticzav yeah sorry was trying to explain the change....

but continuing forward, I have a setup that passes the IMiddlewareGenerator directly to applyMiddleware() and am now encountering this error Error: Type generator exists in middleware but is missing in Schema. it seems to me as though the code in graphql-middleware is not running/generating the generator properly.... is there a specific graphql-middleware version I should be using along with this?

artemzakharov commented 6 years ago

@maticzav I did have graphql-middleware installed, but removing it didn't seem to help. Are you aware of any other libraries that might cause a conflict?

On a side note, do you happen to have a guide for using shield with Apollo Server 2? I've been considering switching over from Yoga, but I haven't found any means to implement your library with them yet.

jonathanheilmann commented 6 years ago

@maticzav yeah sorry was trying to explain the change....

but continuing forward, I have a setup that passes the IMiddlewareGenerator directly to applyMiddleware() and am now encountering this error Error: Type generator exists in middleware but is missing in Schema. it seems to me as though the code in graphql-middleware is not running/generating the generator properly.... is there a specific graphql-middleware version I should be using along with this?

I'm running into the same error using graphql-middleware version 1.7.2 and have no idea on how to solve this problem.

maticzav commented 6 years ago

@JazminGonzalez-Rivero @artemzakharov @jonathanheilmann thanks for the feedback!

Let's first fix the problem this issue is named after. I am unable to reproduce the bug you are all facing. Since the best reproduction explanation, so far, has been to try the provided combinations of package versions, which I also tested, I am unable to conclude anything. It would be super helpful if one of you could tinker together a small repository portraying the bug. This way I can take a look into the problem and fix it if we find its nucleus in graphql-shield or graphql-middleware.


Regarding the Apollo Server issue, yes, there's a way of doing it. I don't have and don't intend to make an article or anything similar explaining the procedure as I hope we will gain middleware support in a matter of days. Nevertheless, I believe I should present the solution; you can use graphql-middleware and accompany it with makeExecutableSchema function provided by graphql-tools.

Since Apollo Server accepts schema as a parameter, you can inject it with no problem.

const schema = makeExecutableSchema({ typeDefs, resolvers })

const schemaWithMiddleware = applyMiddleware(
  schema,
  shield()
)

const server = new ApolloServer({
  mocks: false,
  schema: schemaWithMiddleware,,
});

i hope this is somewhat helpful πŸ™‚

morgothulhu commented 6 years ago

Running into the same issue unfortunately. For reference I use yoga with the Lambda ctor.

maticzav commented 6 years ago

@morgothulhu could you pull together a reproduction repo?

MaksimKlepikov commented 5 years ago

Same here. I'm just yarn upgrade --latest and now getting:

Error: Cannot find module 'graphql-middleware'
    at Function.Module._resolveFilename (module.js:547:15)
    at Function.Module._load (module.js:474:25)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/mnt/share/Git/aerobic-backend/node_modules/graphql-shield/src/shield.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)
    at Function.Module._load (module.js:497:3)

After yarn add graphql-middleware i'm getting:

Error: Type generator exists in middleware but is missing in Schema.
    at new MiddlewareError (/mnt/share/Git/aerobic-backend/node_modules/graphql-yoga/node_modules/graphql-middleware/dist/validation.js:46:23)
    at /mnt/share/Git/aerobic-backend/node_modules/graphql-yoga/node_modules/graphql-middleware/src/validation.ts:17:13
    at Array.forEach (<anonymous>)
    at Object.validateMiddleware (/mnt/share/Git/aerobic-backend/node_modules/graphql-yoga/node_modules/graphql-middleware/src/validation.ts:15:27)
    at addMiddlewareToSchema (/mnt/share/Git/aerobic-backend/node_modules/graphql-yoga/node_modules/graphql-middleware/src/middleware.ts:33:27)
    at normalisedMiddlewares.reduceRight.schema (/mnt/share/Git/aerobic-backend/node_modules/graphql-yoga/node_modules/graphql-middleware/src/middleware.ts:86:13)
    at Array.reduceRight (<anonymous>)
    at applyMiddlewareWithOptions (/mnt/share/Git/aerobic-backend/node_modules/graphql-yoga/node_modules/graphql-middleware/src/middleware.ts:78:77)
    at applyMiddleware (/mnt/share/Git/aerobic-backend/node_modules/graphql-yoga/node_modules/graphql-middleware/src/middleware.ts:129:36)
    at new GraphQLServer (/mnt/share/Git/aerobic-backend/node_modules/graphql-yoga/src/index.ts:137:13)

and

Error: Cannot use GraphQLNonNull "[Competition]!" from another module or realm.

Ensure that there is only one instance of "graphql" in the node_modules
directory. If different versions of "graphql" are the dependencies of other
relied on modules, use "resolutions" to ensure only one version is installed.

https://yarnpkg.com/en/docs/selective-version-resolutions

Duplicate "graphql" modules cannot be used at the same time since different
versions may have different capabilities and behavior. The data from one
version used in the function from another could produce confusing and
spurious results.
    at instanceOf (/mnt/share/Git/aerobic-backend/node_modules/graphql/jsutils/instanceOf.js:37:13)
    at isNonNullType (/mnt/share/Git/aerobic-backend/node_modules/graphql/type/definition.js:157:34)
    at PrismaTypescriptGenerator.TypescriptGenerator.renderFieldType (/mnt/share/Git/aerobic-backend/node_modules/graphql-binding/src/codegen/TypescriptGenerator.ts:309:9)
    at /mnt/share/Git/aerobic-backend/node_modules/graphql-binding/src/codegen/TypescriptGenerator.ts:255:48
    at Array.map (<anonymous>)
    at PrismaTypescriptGenerator.TypescriptGenerator.renderMainMethodFields (/mnt/share/Git/aerobic-backend/node_modules/graphql-binding/src/codegen/TypescriptGenerator.ts:252:8)
    at PrismaTypescriptGenerator.TypescriptGenerator.renderQueries (/mnt/share/Git/aerobic-backend/node_modules/graphql-binding/src/codegen/TypescriptGenerator.ts:190:17)
    at PrismaTypescriptGenerator.render (/mnt/share/Git/aerobic-backend/node_modules/prisma-binding/src/PrismaTypescriptGenerator.ts:13:31)
    at /mnt/share/Git/aerobic-backend/node_modules/prisma-binding/src/bin.ts:69:34
    at step (/mnt/share/Git/aerobic-backend/node_modules/prisma-binding/dist/bin.js:33:23)

Running graphql codegen βœ–

index.ts

import { formatError } from 'apollo-errors';
import { GraphQLServer } from 'graphql-yoga';
import { forwardMiddleware } from './forwards';
import { Prisma } from './generated/prisma';
import { permissions } from './permissions';
import {fragmentReplacements, resolvers} from './resolvers';

import { getUser } from './utils';

const server = new GraphQLServer({
  typeDefs: './src/schema.graphql',
  resolvers,
  resolverValidationOptions: {
    requireResolversForResolveType: false,
  },
  middlewares: [forwardMiddleware, permissions],
  context: ({
    request,
    response,
    fragmentReplacements: middlewareFragmentReplacements,
  }) => ({
    request,
    response,
    user: getUser(request),
    db: new Prisma({
      fragmentReplacements: [
        ...fragmentReplacements,
        ...middlewareFragmentReplacements,
      ],
      // typeDefs: 'src/generated/prisma.graphql', // the auto-generated GraphQL schema of the Prisma API
      endpoint: process.env.PRISMA_ENDPOINT,
      secret: process.env.PRISMA_SECRET, // only needed if specified in `database/prisma.yml`
      debug: false,
      // debug: process.env.NODE_ENV !== 'production'
    }),
  }),
});

package.json

  "dependencies": {
    "apollo-errors": "^1.9.0",
    "bcryptjs": "^2.4.3",
    "graphql": "^14.0.2",
    "graphql-cli": "^2.16.3",
    "graphql-middleware": "^1.7.4",
    "graphql-middleware-forward-binding": "^1.3.2",
    "graphql-shield": "^3.2.4",
    "graphql-yoga": "^1.14.10",
    "jsonwebtoken": "^8.3.0",
    "nodemailer": "^4.6.7",
    "npm-run-all": "^4.1.3",
    "prisma": "^1.10.2",
    "prisma-binding": "^2.1.0"
  },

I discard changes in my package.json and only upgrade graphql-shield from 2.2.5 to 3.2.4 and everything is ok, my current package.json:

  "dependencies": {
    "apollo-errors": "^1.9.0",
    "bcryptjs": "^2.4.3",
    "graphql": "^0.13.2",
    "graphql-cli": "^2.16.3",
    "graphql-middleware-forward-binding": "^1.3.2",
    "graphql-shield": "^3.2.4",
    "graphql-yoga": "^1.14.10",
    "jsonwebtoken": "^8.3.0",
    "nodemailer": "^4.6.7",
    "npm-run-all": "^4.1.3",
    "prisma": "^1.10.2",
    "prisma-binding": "^2.1.0"
  },
maticzav commented 5 years ago

Hey @kevrat πŸ‘‹,

Thank you for posting a reproduction code. You're probably experiencing the issues because your grpahql-yoga version is still on 1.14.10 which doesn't yet pack the new graphql-middleware. I advise you try updating yoga to its latest version (1.16.2) and see if the error is still present.

I hope this solves your problem πŸ™‚

maticzav commented 5 years ago

OK, huge thanks to everyone for posting the reproduction code and contributing to the above discussion. I think I've finally found a pattern in the errors we have seen, here's my examination;

@artemzakharov I am sorry, but I am still unable to reproduce your bug. The steps I take are as follows;

graphql create project
yarn add graphql-shield

This results in graphql-yoga version 1.16.2 and graphql-shield version 3.2.4.

No error is shown.


Error: Type generator exists in middleware but is missing in Schema.

@JazminGonzalez-Rivero

This error occurs due to duplicated graphql-middleware package. graphql-yoga is already packed with the latest graphql-middleware version working with it. Therefore, you shouldn't install a separate one. You can resolve this by removing direct graphql-middleware dependency.


Error: Type generator exists in middleware but is missing in Schema.

@kevrat

This error occurs due to an outdated version of graphql-middleware. To fix it you should update graphql-middleware, in case you are not using Yoga; or graphql-yoga in case you do.

I'll close this issue as it seems we've covered everything hitherto discussed. If anyone finds any other bug related to this topic, don't hesitate to open another question or a reply to this thread. πŸ™‚

MaksimKlepikov commented 5 years ago

As you say i updated graphql-yoga and now i'm getting:

Error: Cannot find module 'graphql-middleware'
    at Function.Module._resolveFilename (module.js:547:15)
    at Function.Module._load (module.js:474:25)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/mnt/share/Git/aerobic-backend/node_modules/graphql-shield/src/shield.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)
    at Function.Module._load (module.js:497:3)
[nodemon] app crashed - waiting for file changes before starting...

my updated package.json

"dependencies": {
    "apollo-errors": "^1.9.0",
    "bcryptjs": "^2.4.3",
    "graphql": "^14.0.2",
    "graphql-cli": "^2.16.7",
    "graphql-middleware-forward-binding": "^1.3.2",
    "graphql-shield": "^3.2.4",
    "graphql-yoga": "^1.16.2",
    "jsonwebtoken": "^8.3.0",
    "nodemailer": "^4.6.7",
    "npm-run-all": "^4.1.3",
    "prisma": "^1.17.1",
    "prisma-binding": "^2.1.6"
  },

if i install it i get

Error: Type generator exists in middleware but is missing in Schema.

If i remove graphql-shield from middlewares all is working. Looks like some packages is conflict. But which. Removing 'graphql-middleware-forward-binding' from middlewares it is don't cause any effect

Also then i yarn install i get some warnings:

warning " > graphql-middleware-forward-binding@1.3.2" has unmet peer dependency "graphql-middleware@^1.3.2".
warning "graphql-middleware-forward-binding > graphql-binding@2.2.5" has incorrect peer dependency "graphql@^0.11.0 || ^0.12.0 || ^0.13.0".
warning "graphql-middleware-forward-binding > graphql-binding > graphql-import@0.5.3" has incorrect peer dependency "graphql@^0.11.0 || ^0.12.0 || ^0.13.0".
warning "prisma-binding > graphql-tools@3.1.0" has incorrect peer dependency "graphql@^0.13.0".
warning " > graphql-shield@3.2.5" has unmet peer dependency "graphql-middleware@^1.6.4".
warning "prisma > prisma-cli-core@1.17.1" has incorrect peer dependency "graphql@^0.12.0 || ^0.13.0".
warning " > prisma-binding@2.1.6" has incorrect peer dependency "graphql@^0.11.0 || ^0.12.0 || ^0.13.0".
warning "prisma-binding > apollo-link@1.2.2" has incorrect peer dependency "graphql@^0.11.3 || ^0.12.3 || ^0.13.0".
warning "prisma-binding > graphql-import@0.5.2" has incorrect peer dependency "graphql@^0.11.0 || ^0.12.0 || ^0.13.0".
warning "prisma-binding > subscriptions-transport-ws@0.9.8" has incorrect peer dependency "graphql@^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.1".
warning " > prettier-tslint@0.4.0" has incorrect peer dependency "typescript@^2.5.3".

GOTCHA! Using graphql": "^0.13.2 don't cause any error. And looks like i don't need this package, so i remove that and everything work. Don't know why i installed it, but it is he who conflicts.

heymartinadams commented 5 years ago

Hi @maticzav! πŸ’―

Receiving the same error β€” could it lie with my codebase?

Error: Type generator exists in middleware but is missing in Schema.
  "dependencies": {
    // ...
    "graphql-middleware": "^1.7.6",
    "graphql-shield": "^3.2.5",
    "graphql-yoga": "^1.13.1",
    "prisma-binding": "^2.1.6",
  },
  "devDependencies": {
    "graphql": "^0.13.2",
    // ...
  }
maticzav commented 5 years ago

Hey @heymartinadams, your graphql-yoga version is outdated.

maticzav commented 5 years ago

@kevrat perfect! I think we should add this to the README. graphql-middleware and graphql-yoga still haven't been updated to the latest GraphQL which might cause the issue that you are describing.

I am so glad it's working now πŸŽ‰

heymartinadams commented 5 years ago

Mmh, @maticzav, upgraded graphql-yoga to 1.16.2, but that error still appears. Could it perhaps be because I’ve moved the rules to another folder? (i.e. does the middleware still reach the rule()(async (parent, { email }, ctx, info) => { ...}) function?)

maticzav commented 5 years ago

Hey @heymartinadams πŸ‘‹,

No, having rules in a separate folder is completely fine. Peeking at your package.json again, however, I spotted you have a separate instance of graphql-middleware alongside graphql-yoga. Try removing that as well.

heymartinadams commented 5 years ago

That totally did the trick, @maticzav πŸ’› Thanks a bunches!! Can’t wait to try and test it out ✨