The mutation examples show that the inputs have to be put under a specific field e.g (@Arg("input")). When I use @Args() instead, I'm getting this error when the server starts
(node:15051) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'target' of undefined
at params.reduce (/web/node_modules/type-graphql/schema/schema-generator.js:240:69)
Is it a must to use @Arg("input")?
This example won't work:
@Mutation(returnType => ItemLike)
async updateItemLikes(@Args() {id, userId}: UpdateItemLikesArgs) {
return ....
}
No, inputs doesn't have to be put under a specific field:
https://github.com/19majkel94/type-graphql/blob/master/tests/functional/resolvers.ts#L61
https://github.com/19majkel94/type-graphql/blob/master/tests/functional/resolvers.ts#L379
Do you have ES6 or newer set in your tsconfig.json?
I use es2015. This is my whole config file:
{
"compileOnSave": true,
"compilerOptions": {
"module": "commonjs",
"target": "es2015",
"rootDir":"./type_src",
"moduleResolution": "node",
"removeComments": false,
"allowSyntheticDefaultImports": true,
"noImplicitAny": false,
"sourceMap": true,
"outDir": "./src",
"experimentalDecorators": true,
"noLib": false,
"declaration": false,
"emitDecoratorMetadata": true,
"lib": ["es6", "dom"],
"types": ["reflect-metadata","system"],
"jsx": "react",
"inlineSources":true,
"skipLibCheck": true
},
"exclude": [
"node_modules"
],
}
Typescript:
@Mutation(returnType => ItemLike)
async updateItemLikes(@Args() {id, userId}: UpdateItemLikesArgs,@Ctx() context:any) {}
This is the generated javascript of the applied decorator:
````
class Reolver{
updateItemLikes({ mid, userId }, context) {
}
}
__decorate([
type_graphql_1.Mutation(returnType => ItemLike_1.ItemLike),
__param(0, type_graphql_1.Args()), __param(1, type_graphql_1.Ctx()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [UpdateItemLikeArgs, Object]),
__metadata("design:returntype", Promise)
], ItemLikeResolver.prototype, "updateItemLikes", null);
````
Does the decorator use class-transformer?
The problem is here:
const argumentType = metadata_storage_1.MetadataStorage.argumentTypes.find(it => it.target === param.getType());
let superClass = Object.getPrototypeOf(argumentType.target);
Looks like UpdateItemLikesArgs has not been found in MetadataStorage.argumentTypes - have you decorated the class with @ArgsType decorator?
@19majkel94
Yes, using ArgsType() instead of InputType() fixes the error.
Is InputType() different from ArgsType()? The doc only shows the use of @InputType() for mutaton
https://github.com/19majkel94/type-graphql/blob/master/docs/validation.md
````
@ArgsType
//@InputType()
export class UpdateItemLikeArgs {
@IsInt()
@Field(type => Int)
id: number;
@IsInt()
@Field(type => Int)
userId: number;
}
````
Is InputType() different from ArgsType()?
Of course! InputType will generate real GraphQLInputType and should be used when you want to have nested object in args:
@InputType()
export class UpdateItemLikeArgs {
@IsInt()
@Field(type => Int)
id: number;
@IsInt()
@Field(type => Int)
userId: number;
}
class Resolver {
@Mutation(returnType => ItemLike)
async updateItemLikes(@Arg("payload") {id, userId}: UpdateItemLikesArgs,@Ctx() context:any) {}
}
will generate:
input UpdateItemLikesArgs {
id: Int!
userId: Int!
}
type Mutation {
updateItemLikes(payload: UpdateItemLikesArgs!): ItemLike!
}
But ArgsType is virtual, it will be flattened in schema:
@ArgsType()
export class UpdateItemLikeArgs {
@IsInt()
@Field(type => Int)
id: number;
@IsInt()
@Field(type => Int)
userId: number;
}
class Resolver {
@Mutation(returnType => ItemLike)
async updateItemLikes(@Args() {id, userId}: UpdateItemLikesArgs,@Ctx() context:any) {}
}
So it will look like this in SDL:
type Mutation {
updateItemLikes(id: Int!, userId: Int!): ItemLike!
}
So you can't use @Args() directly with input type, it can be nested as a field of ArgsType. To mount input field directly to mutation, use @Arg("name") decorator.
Is that clear enough now? 馃槈
Just ran into this myself - might be worth checking when @Args() is used, and providing a helpful error message explaining (or even just linking to this issue thread).
It's described in FAQ:
https://19majkel94.github.io/type-graphql/docs/faq.html#is-inputtype-different-from-argstype
So if the problem is that people use @Args with @InputType or without @ArgsType, I can check and handle that 馃槈
Most helpful comment
Of course!
InputTypewill generate realGraphQLInputTypeand should be used when you want to have nested object in args:will generate:
But ArgsType is virtual, it will be flattened in schema:
So it will look like this in SDL:
So you can't use
@Args()directly with input type, it can be nested as a field ofArgsType. To mount input field directly to mutation, use@Arg("name")decorator.Is that clear enough now? 馃槈