Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using this in a serverless environment (e.g. apollo-lambda-server) #96

Closed
darbio opened this issue Jun 5, 2018 · 29 comments
Closed

Using this in a serverless environment (e.g. apollo-lambda-server) #96

darbio opened this issue Jun 5, 2018 · 29 comments
Labels
Question ❔ Not future request, proposal or bug issue Solved ✔️ The issue has been solved

Comments

@darbio
Copy link

darbio commented Jun 5, 2018

How would I use this library in a lambda execution model?

I tried to implement it as follows, but on the second (and subsequent) calls to the endpoint, I get an error which states:

Schema must contain unique named types but contains multiple types named "Person"

I assume that this is because the schema is being re-built on every request, and therefore creating duplicated types?

handler.ts

import 'reflect-metadata';

import { graphqlLambda } from 'apollo-server-lambda';
import { buildSchema } from 'type-graphql';

import { PeopleController } from './controllers/people/peopleController';

export async function graphqlHandler(event, context, callback) {
    function callbackWithHeaders(error, output) {
        output.headers['Access-Control-Allow-Origin'] = '*';
        callback(error, output);
    }

    const schema = await buildSchema({
        resolvers: [PeopleController]
    });

    const handler = graphqlLambda({ schema: schema });
    return handler(event, context, callbackWithHeaders);
}

person.ts:

import { ID, Field, ObjectType } from 'type-graphql';

@ObjectType()
export class Person {
    @Field() name: string;
    @Field() creationDate: Date;
}

peopleController.ts

import { Arg, Query, Resolver } from 'type-graphql';
import { Person } from './person';

@Resolver()
export class PeopleController {
    items: Person[] = [
        {
            name: 'darbio',
            creationDate: new Date()
        }
    ];

    @Query(returns => [Person], { description: 'Get all the people' })
    async people(): Promise<Person[]> {
        return await this.items;
    }
}
@darbio darbio mentioned this issue Jun 5, 2018
11 tasks
@MichalLytek
Copy link
Owner

Discussion copied from #52

darbio

OK. I saw that in the code above, however I get the following error when I try and use the global scoped metadata. I've confirmed that I am only including type-grahql and not any other graphql packages.

Error: Cannot use GraphQLSchema "[object Object]" 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 (/Users/jamesdarbyshire/Repositories/darb.io/cad/cad-api/.webpack/service/src/index.js:28689:13)
    at isSchema (/Users/jamesdarbyshire/Repositories/darb.io/cad/cad-api/.webpack/service/src/index.js:35013:35)
    at validateSchema (/Users/jamesdarbyshire/Repositories/darb.io/cad/cad-api/.webpack/service/src/index.js:35287:25)
    at assertValidSchema (/Users/jamesdarbyshire/Repositories/darb.io/cad/cad-api/.webpack/service/src/index.js:35312:16)
    at Object.validate (/Users/jamesdarbyshire/Repositories/darb.io/cad/cad-api/.webpack/service/src/index.js:43344:35)
    at doRunQuery (/Users/jamesdarbyshire/Repositories/darb.io/cad/cad-api/.webpack/service/src/index.js:892:38)
    at /Users/jamesdarbyshire/Repositories/darb.io/cad/cad-api/.webpack/service/src/index.js:803:56
    at <anonymous>
    at process._tickDomainCallback (internal/process/next_tick.js:228:7)

answer

@darbio The problem is that the metadata is attached to global scope to make multi-packages work but AWS lambda use the same node.js process for each request, so consecutive schema builds effect in duplicated types&resolvers definition.

Storing built schema in global fix that + save time that would be used to build the schema for each request.

global.schema = global.schema || buildSchemaSync(/*... */);
const schema = global.schema;

According to your error, you need to make sure that there's no duplicated graphql packages in node_modules - check graphql dependecies version of your dependencies, try to upgrade them and run npm dedupe or the one that yarn is prompting you 😉

@MichalLytek MichalLytek added the Question ❔ Not future request, proposal or bug issue label Jun 5, 2018
@darbio
Copy link
Author

darbio commented Jun 5, 2018

There are no duplicated graphql packages - the only package that references graphql is type-graphql.

I have tried npm dedupe and also deleting node_modules and reinstalling everything.

Any other tips to try?

@MichalLytek
Copy link
Owner

Without error-reproducible code repository I'm not able to figure out what's wrong from this amount of informations.
The error is about instanceOf of GraphQLSchema so it looks like a problem of different graphql packages.

@darbio
Copy link
Author

darbio commented Jun 5, 2018

@19majkel94 here is a reproducible code example: https://github.com/darbio/example-type-graphql-serverless

@darbio
Copy link
Author

darbio commented Jun 5, 2018

I think the problem may be with webpack - it doesn't play nicely with graphql. Removing graphql from webpack appears to solve the problem. I've updated the repo to reflect this.

@darbio darbio closed this as completed Jun 5, 2018
@Ponjimon
Copy link

So, what is the solution for this now?

@MichalLytek
Copy link
Owner

@lookapanda Use the global.schema solution

@Ponjimon
Copy link

I did, it did not help, I still get the same error.

@Ponjimon
Copy link

Serverless: [200] {"statusCode":null,"headers":{"Access-Control-Allow-Origin":"*"},"body":null}
Caught error in GraphQL handler Error: Cannot use GraphQLSchema "[object Object]" 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 (redacted/node_modules/graphql/jsutils/instanceOf.js:17:13)
    at isSchema (redacted/node_modules/graphql/type/schema.js:48:35)
    at validateSchema (redacted/node_modules/graphql/type/validate.js:51:25)
    at assertValidSchema (redacted/node_modules/graphql/type/validate.js:76:16)
    at Object.validate (redacted/node_modules/graphql/validation/validate.js:61:35)
    at doRunQuery (redacted/node_modules/apollo-server-core/dist/runQuery.js:110:38)
    at redacted/node_modules/apollo-server-core/dist/runQuery.js:21:56
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:160:7)

Serverless: Warning: context.done called twice within handler 'graphql'!

Serverless: Warning: handler 'graphql' returned a promise and also use a callback!
This is problematic and might cause issues in you lambda.

@Ponjimon
Copy link

Ah, I had to set my project's graphql version to the same as type-graphql.

@MichalLytek
Copy link
Owner

@lookapanda Yes, TypeGraphQL has a direct dependency on graphql-js so it has to match to be merged into one dependency folder by npm.

I think in future release I will reexport everything from graphql-js and warn against duplicated graphql-js by installing it on your own.

@kvarela
Copy link

kvarela commented Jul 27, 2018

Sorry for the newb question, @19majkel94 but what do you mean when you're talking about defining the schema globally? Do you mean just define it outside of the handler?

This code doesn't compile for me:

global.schema = global.schema || buildSchemaSync(/*... */);
const schema = global.schema;

I tried something like this Global.ts:

export class Global {
    public static schema: GraphQLSchema
}

And in my handler:

Global.schema = Global.schema || TypeGraphQL.buildSchemaSync({ resolvers: [UserResolver] });
    const schema = Global.schema;

But I still get:
Error: Schema must contain unique named types but contains multiple types named "User".

@MichalLytek
Copy link
Owner

This code doesn't compile for me:

You need to define custom property in global object:
https://github.com/19majkel94/type-graphql/blob/master/src/declarations.d.ts

Or just cast it to any:

(global as any).schema = (global as any).schema || await buildSchema(/*... */);
const schema = (global as any).schema;

@xamoulin
Copy link

Hi,

So i'm trying to do this (run on apollo-server-lambda) and I have this error:
Expected value of type "Profile" but got: [object Object].
(Profile is a type that I have defined)

The first request works fine but the subsequent doesn't. I store the schema on global has shown above and I use the same version of graphql than type-graphql.

Any ideas ?

Thanks

@suku-h
Copy link

suku-h commented Oct 18, 2018

My graphql version is same in type-graphql and in the project:

"graphql": { "version": "0.13.2", "resolved": "http://registry.npmjs.org/graphql/-/graphql-0.13.2.tgz", "integrity": "sha512-QZ5BL8ZO/B20VA8APauGBg3GyEgZ19eduvpLWoq5x7gMmWnHoy8rlQWPLmWgFvo1yNgjSEFMesmS4R6pPr7xog==", "requires": { "iterall": "1.2.2" } },

package-lock for type-graphql

"type-graphql": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/type-graphql/-/type-graphql-0.14.0.tgz", "integrity": "sha512-LS9Jor6uyTwvV/hSfcYIg9KgFNP7QPgxY8k/ABRsqtH1kAfzj+E10HALogCwySea6O5T84z3g2wCYFcbvBiJcw==", "requires": { "@types/glob": "5.0.36", "@types/graphql": "0.13.4", "@types/node": "10.5.3", "class-validator": "0.9.1", "glob": "7.1.2", "graphql": "0.13.2", "graphql-query-complexity": "0.2.0", "graphql-subscriptions": "0.5.8", "tslib": "1.9.3" }, "dependencies": { "graphql": { "version": "0.13.2", "resolved": "http://registry.npmjs.org/graphql/-/graphql-0.13.2.tgz", "integrity": "sha512-QZ5BL8ZO/B20VA8APauGBg3GyEgZ19eduvpLWoq5x7gMmWnHoy8rlQWPLmWgFvo1yNgjSEFMesmS4R6pPr7xog==", "requires": { "iterall": "1.2.2" } } }

I have also added the following text in app.ts

`(global as any).schema = (global as any).schema || buildSchemaSync({ resolvers })
 const schema = (global as any).schema`

I don't have graphql installed globally.

I have also added to the package.json

"resolutions": { "graphql": "^0.13.2" }

Still I am getting the error:

"Cannot use GraphQLSchema \"[object Object]\" from another module or realm.

@MichalLytek
Copy link
Owner

You need to flatten your dependencies - npm dedupe. Otherwise there're two instances of graphql 0.13.2 so instance of doesn't work and you have Cannot use GraphQLSchema error.

And try v0.15.0 with graphql-js v14.0 😃

@suku-h
Copy link

suku-h commented Oct 18, 2018

@19majkel94 thanks for telling me the solution. Your suggestion also worked perfectly. You should write a medium article on it and even write this solution in the readme.

@MichalLytek
Copy link
Owner

@MichalLytek MichalLytek added the Solved ✔️ The issue has been solved label Oct 22, 2018
@bgdnp bgdnp mentioned this issue Aug 2, 2019
2 tasks
@NoelBaron
Copy link

This code doesn't compile for me:

You need to define custom property in global object:
https://github.com/19majkel94/type-graphql/blob/master/src/declarations.d.ts

Or just cast it to any:

(global as any).schema = (global as any).schema || await buildSchema(/*... */);
const schema = (global as any).schema;

This solved my issues when running type-graphql with apollo-server-lambda. Works perfectly with serverless-offline. 👍

@githubflub
Copy link

githubflub commented Oct 16, 2019

There are no duplicated graphql packages - the only package that references graphql is type-graphql.

I have tried npm dedupe and also deleting node_modules and reinstalling everything.

Any other tips to try?

I had this problem not too long ago. In my case, it was happening because I wasn't properly excluding the node_modules folder from webpack. Once I did, the 'realm' error went away.

Annotation 2019-10-15 220222

@filipsuk
Copy link

What helped me with running serverless-offline was to use sls offline instead of sls offline start

@carlosdubus
Copy link

This worked for me with apollo-server-lambda:

import "reflect-metadata";
const { ApolloServer } = require('apollo-server-lambda');
import { buildSchema } from "type-graphql";
import { resolvers } from "...";

const globalSchema = buildSchema({
    resolvers
});

async function getServer() {
    const schema = await globalSchema;
    return new ApolloServer({
        schema
    });
}

export function handler(event: any, ctx: any, callback: any) {
    getServer()
        .then(server => server.createHandler())
        .then(handler => handler(event, ctx, callback))
}

@daveykane
Copy link

I was having this issue when running locally with the latest version of serverless-offline and after some digging this solved the issue for me, posting here incase it helps anyone else :-)

graphql/graphql-js#2801 (comment)

@RishikeshDarandale
Copy link

RishikeshDarandale commented Mar 4, 2021

I am getting below error in lambda(14.x) consistently:

{
    "errorType": "Error",
    "errorMessage": "Schema must contain uniquely named types but contains multiple types named \"f\".",
    "stack": [
        "Error: Schema must contain uniquely named types but contains multiple types named \"f\".",
        "    at new GraphQLSchema (/var/task/node_modules/graphql/type/schema.js:194:15)",
        "    at Function.generateFromMetadataSync (/var/task/node_modules/type-graphql/dist/schema/schema-generator.js:31:32)",
        "    at Function.generateFromMetadata (/var/task/node_modules/type-graphql/dist/schema/schema-generator.js:16:29)",
        "    at Object.buildSchema (/var/task/node_modules/type-graphql/dist/utils/buildSchema.js:10:61)",
        "    at Runtime.t.graphqlHandler [as handler] (/var/task/src/functions/index.js:1:670)",
        "    at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)"
    ]
}

Does anybody aware of this one?

[Note: everything works as expected with serverless-offline]

@98sean98
Copy link

@RishikeshDarandale +1
I'm facing the same thing using typegraphql-prisma plugin.

@RishikeshDarandale
Copy link

@RishikeshDarandale +1
I'm facing the same thing using typegraphql-prisma plugin.

@98sean98 , my issue happens when the webpack devtool property set to source-map.

If it is set to eval-cheap-module-source-map, then it works as expected.

@omar-dulaimi
Copy link

@RishikeshDarandale @98sean98 I'm facing the same issue as well:

{
    "errorType": "Error",
    "errorMessage": "Schema must contain uniquely named types but contains multiple types named \"h\".",
    "stack": [
        "Error: Schema must contain uniquely named types but contains multiple types named \"h\".",
        "    at new GraphQLSchema (/var/task/node_modules/graphql/type/schema.js:194:15)",
        "    at Function.generateFromMetadataSync (/var/task/node_modules/type-graphql/dist/schema/schema-generator.js:31:32)",
        "    at Object.buildSchemaSync (/var/task/node_modules/type-graphql/dist/utils/buildSchema.js:20:55)",
        "    at Object.t.default (/var/task/src/index.js:1:5251373)",
        "    at Object.80341 (/var/task/src/index.js:1:5271735)",
        "    at n (/var/task/src/index.js:1:5439183)",
        "    at /var/task/src/index.js:1:5439223",
        "    at Object.<anonymous> (/var/task/src/index.js:1:5439330)",
        "    at Module._compile (internal/modules/cjs/loader.js:999:30)",
        "    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)"
    ]
}

@RishikeshDarandale
Copy link

@omar-dulaimi , if you are using webpack, then can you try updating devtool as suggested in my above comment?

@omar-dulaimi
Copy link

@RishikeshDarandale Yeah that does solve the issue, thanks.

However, I was hoping to keep the sourcemaps. So not sure what the real issue here is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question ❔ Not future request, proposal or bug issue Solved ✔️ The issue has been solved
Projects
None yet
Development

No branches or pull requests