Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • Oct 19 23:42
  • Oct 19 14:41
    tnolan8 commented #453
  • Oct 19 12:28
    jtassin closed #730
  • Oct 19 10:58
    slaypni commented #51
  • Oct 19 09:58
    geoyws commented #51
  • Oct 19 08:34
    MichalLytek commented #727
  • Oct 19 08:33
    MichalLytek commented #727
  • Oct 19 08:29
    borremosch commented #727
  • Oct 19 03:56
    a-suenami commented #251
  • Oct 18 20:00
    MichalLytek milestoned #734
  • Oct 18 20:00
    MichalLytek assigned #734
  • Oct 18 20:00
    MichalLytek labeled #734
  • Oct 18 20:00
    MichalLytek labeled #734
  • Oct 18 20:00
    MichalLytek milestoned #726
  • Oct 18 19:59
    MichalLytek assigned #726
  • Oct 18 17:08
  • Oct 18 17:04
    blueset opened #734
  • Oct 18 17:02
    MichalLytek edited #733
  • Oct 18 17:02
    codecov[bot] commented #733
  • Oct 18 17:01
    codecov[bot] commented #733
Tiago Braga
@tibraga
Hi guys, could some one say to me what's difference of nestjs-graphql to type-graphql ? I'm studying thoses to choice one and to adopt in my project.
4 replies
DarkLite1
@DarkLite1

We currently have this working query:

query {
  viewerPreference {
    id
    language
  }
}

But want to change it to this:

query {
  viewer {
    preference {
      id
      language
     }
  }
}

Working code:

// PreferenceResolver.ts
@Resolver()
export class PreferenceResolver {
  @Query(() => Preference, { nullable: true })
  async viewerPreference(@Ctx() ctx: { user: Account }) {
      const account = await Account.findOne( { id: ctx.user.id }, { relations: ['preference'] } )
      return account?.preference
  }

To get to the desired query structure we created a new Viewer type

@ObjectType()
export class Viewer {
  @Field(() => Preference)
  preference: Preference
}

The issue we have is to resolve the field preference of the viewer type. We could simply copy the working viewerPreference method/query in the ViewerResolver.ts file. But when we add more objects than preference later on it will become a mixed bag. What is the best way to keep logic of the preferences in a separate file and just point to it from the ViewerResolver.ts? Is this what the field @FieldResolver() does?

@Resolver()
export class ViewerResolver {
  @Query()
  preference() {
    return Preference.find()
  }
}

Thank you for putting us on the right track.

17 replies
Bruno Cordioli Machado
@brunocordioli072
How can i access apollo context on resolver constructor? please help s2
const server = new ApolloServer({
  schema,
  introspection: true,
  playground: true,
  context: function (event: any) {
    let req: Request = event.event;
    return { authorization: req.headers.authorization };
  },
});
@Resolver((of) => Random)
export class RandomResolver {
  constructor(@Ctx() ctx: Context) {
    // this returns undefined always
    if (ctx.authorization) console.log(ctx.authorization);
  }
  @Query(() => Random)
  randomQuery(@Ctx() ctx: Context) {
    // this returns the token as was supposed to
    if (ctx.authorization) console.log(ctx.authorization);
    return {};
  }
}
7 replies
Dregond Rahl
@DregondRahl_twitter
hey all, just a bit confused. but typegraphql doesn't have build option. how would it be deployed in a production environment ?
1 reply
Tianyuan Chu
@TianyuanC

Hello everyone, is it possible to chain the root query in the mutation response?
As suggested in graphql rules https://graphql-rules.com/rules/mutation-payload-query

Goal:

type Mutation {
  createPost(field: CreatePostInput): CreatePostResult
}

type CreatePostResult {
   data: Post
   query: Query!
}
@ObjectType()
export default class CreatePostResult {
    @Field({ nullable: true })
    data: Post;

    @Field(() => ...)
    query: ...;
}

Is there any "magic type" I could use to achieve this?
I'm also thinking about passing the root query through @Ctx after the final schema has been built (but I also got stuck there)

Thank you so much in advance for any guidance or suggestion!

3 replies
gmwill934
@gmwill934
Hey there! Has anyone integrated auth0 with next js and type graphql. I'm having trouble understanding how to secure different resolvers. normally with a rest api you would add middleware to your end points but I can't do that with graphql since only one end point is exposed... Any help or pointers would be appreciated!
2 replies
Ghost
@ghost~5f725ccbd73408ce4ff020e4

hello,
how can I use the paginator example with a union type ? https://typegraphql.com/docs/generic-types.html#basic-usage

I mean, PaginatedResponse expects a class, not a type*

2 replies
Kunjan Dalal
@kunjee17
Any idea how to right below kind of code in Type Graphql
Appointment(canceled: Boolean): [DateScaler!]!
10 replies
Wise Introvert
@wise-introvert
I'm using a custom auth checker in my apollo-server-express application. How do I attach a user object to request after the user has been verified?
3 replies
Mars Dong
@kdong007

How do I do a @Autherized() rule based on resource Id? for example I have:

class Account { 
   @Field()
   id: string
   @Field()
   somePrivateData:string 
}

I only want to give access to user with who log in with this account. But I can't just do a "LOGIN_USER" because that will give access to all logged in users

2 replies
Zefex Developer
@zefexdeveloper

I'm studying to implement a comment system that allows someone to comment in a few places just like GitHub does with an issue and pull request using TypeGraphQL.

From GitHub schema:

input AddCommentInput {
  """
  The contents of the comment.
  """
  body: String!

  """
  A unique identifier for the client performing the mutation.
  """
  clientMutationId: String

  """
  The Node ID of the subject to modify.
  """
  subjectId: ID! @possibleTypes(concreteTypes: ["Issue", "PullRequest"], abstractType: "IssueOrPullRequest")
}

In order to execute this it would be something like this:

mutation {
  addComment(input: {subjectId: "MDU5SXNddWU3MTM5zTc1Nzc=", body: "hi", clientMutationId: "MDQ63XNlcxQ5Njk0OTU2"}) {
    commentEdge {
      node {
        body
      }
    }
  }
}

They use the subjectId to detect if it's an issue or a pull request and creates the comment.

I like this approach but how would that work on the resolver side? How to know when the user is writing a comment on an issue or a pull request?

There's also @possibleTypes directive on the schema, how would that work?

Thank you

6 replies
tafelito
@tafelito
@MichalLytek can the authChecker be an async function? I run into an issue becuase of this. Is it possible to return a promise?
7 replies
Edouard Bougon
@EdouardBougon
This message was deleted
7 replies
gmwill934
@gmwill934
Can anyone share their way of handling errors using type-graphql? Would be interested to see some approaches. I currently use unions and create responses for my entities.
huyha
@huyhavmodev

I have an enum like that:

export enum Status {
  OPEN = 'Open',
  CLOSED = 'Closed',
  CANCELLED = 'Cancelled',
  COMPLETED = 'Completed',
  NO_RESPONSE = 'No response',
}
registerEnumType(Status, {
  name: 'Status',
});

The data was stored in my database is enum value but Graphql returns enum key.
How can I share enum between backend and frontend?
I'm using react typescript for frontend and graphql-codegen for generating type.
I want to show exactly enum value on frontend.
Thanks for see

3 replies
dan-klasson
@dan-klasson
I've setup my server to use nested input type. Everything is working as expected on the server side and I the client documentation is generated properly. But how do I use this on the client side? Isn't it possible to do nested input types in GraphQL?
I'm trying to do something like this:
  mutation foo(
    input: FooInput! {
      $settings: FooSettingsInput!
    }
    $fooId: Int!
  ) {
    foo(
      input: {
        settings: $settings
      }
      fooId: $fooId
    ) {
      document
      settings {
        offset_x
        offset_y
        product_shadow
        product_levels
        product_depth
        product_shrinkage
        horizontal_focal_depth
        vertical_focal_depth
      }
    }
  }
1 reply
Zefex Developer
@zefexdeveloper

I'm implementing the relay specification on TypeGraphQL and for that I created an interface like this:

@InterfaceType('Node')
export abstract class NodeInterface {
  @Field(() => ID, { name: 'id' })
  globalId!: string
}

And I implement that on my object type like this:

@Entity('comments')
@ObjectType('Comment', { implements: NodeInterface })
export class CommentEntity extends NodeInterface {
  @PrimaryGeneratedColumn()
  id!: number

  @Column('text')
  @Field()
  content!: string

  @CreateDateColumn()
  @Field()
  created_at!: Date

  @UpdateDateColumn()
  @Field()
  updated_at!: Date
}

I also have a NodeResolver

@Resolver()
export class NodeResolver {
  @Inject()
  private commentService!: CommentService

  @Query(() => NodeInterface, { nullable: true })
  async node(
    @Arg('id', () => ID) globalId: string
  ): Promise<NodeInterface | null | undefined> {
    const { type, id } = fromGlobalId(globalId)

    if (type == 'Comment') {
      return this.commentService.findById(id)
    }

    return null
  }
}

It works perfectly but the only thing missing is the globalId resolver to return a toGlobalId. I thought about doing that on the interface itself so when I extend that on any object type it would work out of the box but I don't know how to get access to the info of the resolver.

The original implementation in relay looks like this: https://github.com/graphql/graphql-relay-js/blob/f00bad1395eed1738264f41c35e3901dddff1559/src/node/node.js#L112-L124

resolve: (obj, _args, context, info) =>
      toGlobalId(
        typeName ?? info.parentType.name,
        idFetcher ? idFetcher(obj, context, info) : obj.id,
      ),

It receives the object and the info, and pass it down to toGlobalId to it can generate a base64 global id from Comment:5 (for example)

Any idea on how I can get the parent object and info on the resolver there on the interface?

7 replies
Zefex Developer
@zefexdeveloper

I can't make the query return to allow null on array

@Query(() => [NodeInterface], { nullable: true })

Is making the field be like this [Node!] but I want it to be like this [Node]!, it will return an array but the content can be either a Node or null

10 replies
Emil Walser
@emme1444

Hi! New to Gitter, but have a question that needs an answer.

I'm trying to build a schema based on my resolvers. I'm using apollo-server-express, the thing is that I'm calling buildSchema with an imported array of the resolver classes. Whenever I create an array inline beside the resolvers field in the BuildSchemaOptions object and import the resolver classes directly it works. However, as soon as I import an exported array (from src/resolvers/index.ts) of resolvers it throws me this daunting error (below). It looks like types aren't compatible but I don't quite understand it fully.

Type '(typeof HelloResolver | typeof UserResolver)[]' is not assignable to type 'readonly [Function, ...Function[]] | [Function, ...Function[]] | readonly [string, ...string[]] | [string, ...string[]]'.
  Type '(typeof HelloResolver | typeof UserResolver)[]' is not assignable to type '[string, ...string[]]'.
    Property '0' is optional in type '(typeof HelloResolver | typeof UserResolver)[]' but required in type '[string, ...string[]]'.

27       resolvers: resolvers,
         ~~~~~~~~~

  node_modules/type-graphql/dist/utils/buildSchema.d.ts:10:5
    10     resolvers: NonEmptyArray<Function> | NonEmptyArray<string>;
           ~~~~~~~~~
    The expected type comes from property 'resolvers' which is declared here on type 'BuildSchemaOptions'

src/resolvers/index.ts

import { HelloResolver } from "./HelloResolver";
import { UserResolver } from "./UserResolver";

export const resolvers = [HelloResolver, UserResolver];
export default resolvers;

src/index.ts snippet

const apolloServer = new ApolloServer({
    schema: await buildSchema({
      // resolvers: [HelloResolver, UserResolver], // works
      resolvers: resolvers, // fails
    }),
  });

Thanks for any help received!

5 replies
Yusuf Emirhan
@yemirhan
Hello, I'm trying to compile my code with tsc, it compiles, but after compilation running node dist/index.js gives me this error
import { Field, ObjectType } from 'type-graphql'
^^^^^^

SyntaxError: Cannot use import statement outside a module
2 replies
Mantas Morkūnas
@bernessco
Hey! I'm trying to create a subscription which returns Union type, but I get 'NoExplicitTypeError: You need to provide explicit type for' error. Same type works for query resolver. Maybe there is an example somewhere ?
5 replies
Nathan
@nspaeth

Hi, I've recently updated to the latest version from ~.17 or something. Since doing so I'm having trouble getting things working in the playground. For example, when using this query:

query myProfile {
  id
}

I get the error:
"Cannot query field \"id\" on type \"Query\"."
For reference, my resolver looks like this:

@Query(() => Profile, { nullable: true })
    async myProfile(
        @Ctx() context: Context,
    ) {
        const token = context.getUser()
        const { user } = token
        const profile = user
            ? await Profile.findOne({ user: { id: user.id } })
            : null
        return profile
    }

Any pointers to what might be wrong?

2 replies
John Jerald De Chavez
@jjdechavez029_gitlab
Hello evryone, I'm new to the type-graphql and I would like to ask whats the difference of this kind implementation with typegoose? which its better to use. thanks
import { ObjectId } from "mongodb";

export class Recipe {
  @Field()
  readonly _id: ObjectId;
}
import {ID} from 'type-graphql';

export class User {
  @Field(() => ID)
  public id?: string;
}
7 replies
jasenp-ticketek
@cjnoname

Hi guys, I just had a problem using Typegraphql 1.0.0 + graphql 15.3.0 with webpack. I have been using this library for over two years and it worked well with webpack. However the issue happens after I upgraded this package to 1.0.0 from 0.18.0-beta.9 and updated graphql lib from 14.6.0 to 15.3.0.

It just cannot build. Console shows some errors about the assertSchema function on graphql lib. I'm using Typegraphql to generate the schema.

2 replies
Jaskeerat Sethi
@jskrt
Hey, I'm seeing an issue where making a @Field with both a name option and nullable = true option marks the field as non-nullable. This this just me?
2 replies
James R Lowrey
@JarLowrey
My date is stored as '2019-11-02' in Postgres DB. field is type=>"date" on the model. When I try to return thru a resolver query, I get "Unable to serialize value '2019-11-02' as it's not instance of 'Date'". If I change the models' time to timestamp, precision 0 and re-seed the DB it returns fine. Any way to get this working properly, or am i forced into the workaround?
Yusuf Emirhan
@yemirhan

Hi, I'm trying to define an object type using typegoose and i get this error whatever i do
Schema must contain uniquely named types but contains multiple types named "User".

These are my codes:
User.ts

@ObjectType()
export class User {
  @Field(() => ID)
  readonly _id: ObjectId;

  @Field(() => String)
  @Property({ required: true, unique: true })
  email: string;

  @Field(() => String, { nullable: true })
  @Property({ required: true, unique: true })
  username: string;

  @Property({ required: true })
  password: string;

  @Property()
  tokenVersion: number;
}

Post.ts

@ObjectType()
export class Post {
  @Field()
  readonly _id: ObjectId;

  @Field()
  @Property({ required: true })
  title: string;

  @Field({ nullable: true })
  @Property()
  description?: string;

  @Field(() => User)
  @Property({ ref: User, required: true })
  author: Ref<User>;
}
alexisdray
@alexisdray

hello all, i'm wondering if type-graphql allows for standard type definitions in the field specification for non primitives at all

type Profile = {
 somefield: string
someotherfield: string 
}

@ObjectType({ description: "Object representing user" })
export class User {
  @Field()
  id: string

  @Field((type) => Profile)
  profile: Profile

initially this seems to compile if I leave out the argument from the @Field decorator
but then apollo throws an error

Unable to infer GraphQL type from TypeScript reflection system

I understand that best practice is to create a decorated class for every type equivalent (i.e. the whole point of code first)

however i'm working off a predefined SDL, written by hand, which was then converted into standard typings.
if i 100% need to convert SDL to classes, that's no problem, and plugin for graphql codegen certainly makes this easier

but i just wanted to understand the principles and 'limitations' of the lib properly

(using "type-graphql": "^1.0.0",)

3 replies
James R Lowrey
@JarLowrey

Why cant we use TypeORM class definition as InputType?

@ArgsType()
class AddArgs {
@Field()
@ValidateNested()
obj:MyEntity;
}

@Entity()
@ObjectType()
export class MyEntity extends BaseEntity {...}

givers error:Cannot determine GraphQL input type for 'obj' of 'AddArgs' class. Does the value used as its TS type or explicit type is decorated with a proper decorator or is it a proper input value?

If I add @InputType() to MyEntity I get Error: Schema must contain uniquely named types but contains multiple types named "MyEntity".

Am I forced to create a new MyEntityInput class, and why is that?

1 reply
Martim de Carvalho e Sousa Pinto da Silva
@motapinto

Hey! I am using type-graphl with apollo-server but I am getting a error that I can't fix! It's a recurring one so after much research and keep finding non solution I decided to post here.
So here is my resolver function:

@query((returns) => ProductType, {nullable: true}) 
async product(@arg('search') search: string) { 
    return await ProductModel.getProductsBySearch(search); 
}

This is my object type Product:

@objectType()
export default class ProductType {
@field()
readonly _key: string;

@field()
@Length(0, 20)
name: string;

@field()
@Length(0, 100)
description: string;

@field((type) => float)
@min(0)
price: number;

@field((type) => int)
@ISINT()
units: number;

@field((type) => [String], {nullable: true})
@isArray()
images: string[];

@field((type) => float, {defaultValue: 0.0})
@min(0)
@max(5)
rating: number;

@field((type) => UserType)
producer: UserType;

@field({defaultValue: Date.now()})
@isDate()
publishedAt: Date

@field((type) => LocationType)
location: LocationType;

@field((type) => [String])
@isArray()
@isnotempty()
@arrayNotEmpty()
@isin(['fruits', 'veggies', 'dairy', 'eggs', 'chicken',
'pork', 'poultry', 'red meat', 'seafood'])
categories: string[]
}

And when I do on graphql:

query getProducts { product(search: "chicken") { name, } }

It returns the error:

Cannot return null for non-nullable field ProductType.name..

Can anyone help me? I thought that by making the { nulable: true} flag on the resolver function it alowed be to return null. I think the problem is that when it does no return nothing and I am asking for the name it gives that problem. BUt how do I solve it. HOw do I say that the ProductType that returns can be not found and return empty, without declaring every field as nullable?

James R Lowrey
@JarLowrey
@motapinto do you have @Entity() on above your @ObjectType?
15 replies
shiz nvm i was confused with my libraries
gmwill934
@gmwill934
Would you recommend using apollo-server-express for production?
Wai Phyo Naing
@waiphyo285
MichalLytek/type-graphql#728 here is my posting issue and please check this in.
Preet Parekh
@preetjdp
Has anybody gotten TypeGraphQL to work with babel, hitting an issue with the FieldResolver.
Preet Parekh
@preetjdp
This is the error that I get
(node:9735) UnhandledPromiseRejectionWarning: Error: Unable to find type metadata for input type or object type named ''
    at /home/preetjdp/proj/node_modules/type-graphql/dist/metadata/metadata-storage.js:184:27
    at Array.forEach (<anonymous>)
    at MetadataStorage.buildFieldResolverMetadata
alexisdray
@alexisdray

hello all, any there a strong opinion about whether to use typedi versus graphql-modules/core /graphql-modules/di for dependency injection?

michal has kindly shown us examples with both.
previously using DI shipped with nestJS, so i guess i'm looking for closest to that. NPM trends shows typedi to be the clear winner, but it's been around longer so....

6 replies
Wai Phyo Naing
@waiphyo285

Hello everyone, I have to working with createUnionType to reference multiple objectType using refPath. I don't know can it surely work or not. please discuss this issue.

export const RefRoomUnion = createUnionType({
  name: 'RefRoomUnion', 
  types: () => [ City, Township, RoomTopic ],
  resolveType: (value: any) => {
    if ('City'  in value) return "City"
    if ('Township' in value) return "Township"
    if ('RoomTopic' in value) return "RoomTopic"
    return undefined;
  }
});

/* ChatRoom Schema */

@ObjectType()
export class ChatRoom {
  @Field(_type => ID)
  _id: String;

  @Field(_type => RefRoomUnion,{ nullable: true })
  @Property({ required: true, refPath: "refRoom" })
  referenceid: Ref<typeof RefRoomUnion>;

  @Field(_type => RefRoomType, { nullable: true })
  @Property({ required: true, enum: Object.values(RefRoomType), index: true })
  refRoom: RefRoomType;
}

export const ChatRoomModel = getModelForClass(ChatRoom);

As above ChatRoom objectType is clear to intend referencing multiple objectType. And imported RefRoomType enum and sample @Resolver are here.

export enum RefRoomType {
  City = "City",
  Township = "Township",
  RoomTopic = "RoomTopic"
};

registerEnumType(RefRoomType, {
  name: "RefRoomType", // this one is mandatory
  description: "The basic room types", // this one is optional
});

@Query(() => [ChatRoom]) // [ChatRoomModel] return schemas
    async returnAllChatRooms(){
      return await ChatRoomModel.find().populate("referenceid"); // ChatRoomModel
  };

The error I can't solve easily is following.

query {
      returnAllChatRooms {
        _id
        description
        referenceid {
          __typename
          ... on City {
            city
          }
          ... on Township {
            township
          }
          ... on RoomTopic {
            roomtopic
          }
        }
     }
  }

Then error message show like this.

 {
  "errors": [
    {
      "message": "Cannot read property 'type' of undefined",
      "locations": [
        {
          "line": 5,
          "column": 5
        }
      ],
      "path": [
        "returnAllChatRooms",
        0,
        "referenceid"
      ],
      "extensions": {
        "code": "INTERNAL_SERVER_ERROR",
        "exception": {
          "stacktrace": [
            "TypeError: Cannot read property 'type' of undefined",
            "    at Function.<anonymous> (C:\\Users\\HP\\Documents\\nwt\\fishadapt_chatroom\\node_modules\\type-graphql\\dist\\schema\\schema-generator.js:427:95)",
            "    at Generator.next (<anonymous>)",
            "    at fulfilled (C:\\Users\\HP\\Documents\\nwt\\fishadapt_chatroom\\node_modules\\tslib\\tslib.js:112:62)",
            "    at processTicksAndRejections (internal/process/task_queues.js:93:5)"
          ]
        }
      }
    },
  ...
}
Michał Lytek
@MichalLytek
@waiphyo285 please stop spamming your issue. You've already posted issue on GitHub and I will take a look at it soon. The issue is that you're returning undefined so it cannot determine the interface type implementation.
Wai Phyo Naing
@waiphyo285
Sorry sir, it is tightly difficult for me. I'll try. Thanks.
2 replies
adsee
@adsee42

Hi everyone. I'm using TypeGraphQL with typeorm to build an apollo server.
With typeorm entity's findAndCount, I can search for rows based on some conditions.
This is the query in the resolver

  @Query((returns) => [Contact], { nullable: true })
  async searchContacts(
    @Args() { order, limit, offset }: SearchContactArgs,
    @Ctx() { user }: Context
  ): Promise<ContactsResponse | undefined> {
    if (!user) throw new Error("Unauthorized!");

    const conditions: FindManyOptions = {
      take: limit,
      skip: offset,
    };
    if (!!order && Object.keys(order).length !== 0) {
      conditions.order = order;
    }

    const [records, totalCount] = await Contact.findAndCount({ ...conditions });
    return { records, totalCount };
  }

And SearchContactArgs is defined as:

@ArgsType()
export class SearchContactArgs {
  // how to define this?
  @Field((type) => Object, { nullable: true })
  order?: { [P in keyof Contact]?: "ASC" | "DESC" | 1 | -1 };

  @Field((type) => Int, { defaultValue: 10 })
  limit?: number;

  @Field((type) => Int, { defaultValue: 0 })
  offset?: number;
}

I tried to build the conditions as typeorm's FindManyOptions, but I don't know how to define order's type inSearchContactArgs.
The console logs showed Cannot determine GraphQL input type for 'order' of 'SearchContactArgs' class. Does the value used as its TS type or explicit type is decorated with a proper decorator or is it a proper input value?
Sorry if this is a noob question, I'm still learning typescript and graphql.
Any comment would be very helpful! Thanks!

4 replies
Martim de Carvalho e Sousa Pinto da Silva
@motapinto

Hey guys! I have a new problem. It seems that the validation for me is not working can anyone help me?
I have here the Product Input :

@inputType()
export default class AddProductInput implements Partial<ProductType> {
  @field()
  name: string;

  @field()
  description: string;

  @field((type) => float)
  price: number;

  @field((type) => int)
  units: number;

  @field((type) => [ImageInput], {nullable: true})
  images: ImageInput[];

  @field((type) => UserInput)
  producer: UserInput;

  @field((type) => LocationInput)
  location: LocationInput;

  @field((type) => [String])
  categories: string[]
}

And here the product type:

@objectType()
export default class ProductType {
  @field()
  readonly _key: string;

  @field({nullable: true})
  @length(0, 20)
  name?: string;

  @field({nullable: true})
  @length(0, 100)
  description?: string;

  @field((type) => float, {nullable: true})
  @min(0)
  price?: number;

  @field((type) => int, {nullable: true})
  units?: number;

  @field((type) => [ImageType], {nullable: true})
  images?: ImageType[];

  @field((type) => ReviewType, {nullable: true})
  review?: ReviewType;

  @field((type) => UserType, {nullable: true})
  producer?: UserType;

  @field({defaultValue: Date.now()})
  publishedAt?: Date

  @field((type) => LocationType, {nullable: true})
  location?: LocationType;

  @field((type) => [String], {nullable: true})
  @isNotEmpty()
  @arrayNotEmpty()
  @isIn(['fruits', 'veggies', 'dairy', 'eggs', 'chicken',
    'pork', 'poultry', 'red meat', 'seafood'])
  categories?: string[]
}

What is happening is for example I can add products with any category I want that is not defined on the validation, or add a -1 on the price, and it adds in the database. How should I do this? I had previously all the validation on the object type and didn't work so I changed to the object input but it's still not working :( . Basically any of the validation I defined is not validating

3 replies
Martim de Carvalho e Sousa Pinto da Silva
@motapinto
@MichalLytek I have two more questions. If you could explain some definitions I would be very grateful and may be of use to other developers. Firstly, is it possible and should I use class validator with Args? Secondly, why should I use Args? For mutation can't I just use Input objects?
Michał Lytek
@MichalLytek
@motapinto try before asking and read faq in docs
Slmii
@Slmii

Hi guys, got a question regarding the @FieldResolver

export class UserResolver {
    @FieldResolver(type => [Trip])
    trips(@Root(): user: User) {
        return TripService.getUserTrips(user.id)
    }
}

export class TripResolver {
    @FieldResolver(type => User)
    user(@Root() trip: Trip) {
        return UserService.getOne(trip.userId);
    }
}
export class User {
    ...
    @Field(type => [Trip])
    trips!: Trip[];
}

export class Trip {
    ...
    @Field(type => User, { nullable: true })
    user!: User;
}

so when I execute the query users and relation trips I can see in the query log that its executing an SQL query to the trips table for each found user result.

users {
    ...
    trips {
        name
    }
}

This is of course the N+1 issue of GraphQL, but I am also using Prisma which has a built in dataloader. But when I query the trips and relation user

trips {
    ...
    user {
        name
    }
}

I can see that its grouping them nicely together for each found trip into 1 query to the user table. Is that because the trips in the user query is an array and the userin the tripsquery is a single object? I cant really figure out why its doing that. Anyone care to explain?

Checkium
@fuwwy
Hey there, I'm using type-graphql with typeorm and need a way for typeorm to only query the selected fields
I've seen this question in a bunch of different places but couldn't find a proper answer, so I decided to ask here
3 replies
Andrew Mitchell
@andrewgeorgemitchell

Hey all, I'm working on building up some basic crud operations in a base resolver that all the other resource resolvers inherit from, I have the queries working just fine, but I seem to be running into an issue when it comes to the input types for the createOne mutation specificallly this error:

"type": "CannotDetermineGraphQLTypeError",
"message": "Cannot determine GraphQL input type for argument named 'input' of 'createOne' of 'AppointmentResolver' class. Is the value, that is used as its TS type or explicit type, decorated with a proper decorator or is it a proper input value?"

Here is my base.resolver.ts

function createBaseResolver<T extends ClassType>(
    suffix: string,
    objectTypeCls: T,
) {
    @Resolver(() => BaseResourceModel, { isAbstract: true })
    abstract class BaseResolver {
        @FieldResolver(() => ID)
        protected id(@Root() { _id }: any) {
            return _id;
        }

        @Query(() => [objectTypeCls], { name: `${suffix.toLowerCase()}s` })
        async getAll(): Promise<T[]> {
            const resource = getModelForClass(objectTypeCls);
            const resources = await resource.find();
            return resources.map(u => u.toObject());
        }

        @Query(() => objectTypeCls, { name: `${suffix.toLowerCase()}` })
        async getOne(@Arg('input') { id }: GetOneArgs): Promise<T[]> {
            const resource = getModelForClass(objectTypeCls);
            const resourceById = await resource.findById(id);
            return resourceById.toObject();
        }

        @Mutation(() => objectTypeCls, { name: `create${suffix}` })
        async createOne(@Arg('input', () => objectTypeCls) resourceInput: T): Promise<any> {
            const resource = getModelForClass(objectTypeCls);
            const newResource = await resource.create(resourceInput as any);
            return newResource;
        }
    }

    return BaseResolver;
}

export default createBaseResolver;

and here is a resource.resolver using the base.resolver.ts:

@Resolver(Appointment)
class AppointmentResolver extends createBaseResolver('Appointment', Appointment) {
    @FieldResolver()
    patient(@Root() { patientId }: Appointment) {
        const patient = getModelForClass(Patient);
        return patient.findById(patientId);
    }
}

export default AppointmentResolver;

I figure I'm missing something about how to generate @InputTypes dynamically? but I'm not sure how I would do that? Any help would be greatly appreciated, this library is amazing and this is the last piece missing to my implementation being fully ready!

7 replies
Paramjeet S Desai
@Paramjeet2810

I want to profile each resolver so that I know how much time is taken by them.
Question 1: How to do so?

I found one approach using a middleware

Code:
export const ResolveTime: MiddlewareFn = async ({ info }, next) => { const profiler = logger.startTimer(); await next(); profiler.done({ message: 'Ending ResolveTime middleware: ${info.parentType.name}.${info.fieldName}' }); };

const schema = await buildSchema({ ..., globalMiddlewares: [ResolveTime], });

Question 2: Is this a correct approach? If yes, how much overhead is added because of this middleware?

On a side note profiler is an internal function created which returns the time taken.

1 reply
Martim Pinto Silva
@MartimMotaPinto_twitter

Hello! I am having some good practices issues that I wanted to confirm. So basically I have a product type with many fields, one of which being an array of reviews. I added a get method on the product type to get the average of all reviews:

@objectType()
export default class ProductType {
  @field()
  readonly _key: string;

  @field({ nullable: true })
  name?: string;

  @field({ nullable: true })
  description?: string;

  @field((type) => float, { nullable: true })
  price?: number;

  @field((type) => int, { nullable: true })
  units?: number;

  @field((type) => [ImageType], { nullable: true })
  images?: ImageType[];

  @field((type) => [ReviewType], { nullable: true })
  reviews?: ReviewType[];

  @field({ defaultValue: Date.now() })
  publishedAt?: Date;

  @field((type) => LocationType, { nullable: true })
  location?: LocationType;

  @field((type) => [CategoryType], { nullable: true })
  categories?: CategoryType[];

  @field((type) => Float, { nullable: true })
  get averageRating(): number {
    return (
      this.reviews.reduce((prev, curr) => prev + (curr.rating || 0), 0) /
      this.reviews.length
    );
  }
}

The question is should I have on the Product Input an averageRating value as input? I don't want to do this since I will never input an array of reviews but if I don't it will give me an errors. Here is the Product Input:

@inputType()
export class CommonProductInput implements Partial<ProductType> {
  @field()
  @length(0, 20)
  name: string;

  @field()
  @length(0, 100)
  description: string;

  @field((type) => float)
  @min(0)
  price: number;

  @field((type) => int)
  @min(1)
  units: number;

  @field((type) => [ImageInput], { nullable: true })
  images: ImageInput[];

  @field((type) => LocationInput)
  location: LocationInput;

  @field((type) => [CategoryInput])
  @isNotEmpty()
  @arrayNotEmpty()
  categories: CategoryInput[];
}

@inputType()
export class AddProductInput extends CommonProductInput {
  @field((type) => UserInput)
  producer: UserInput;
}

@inputType()
export class UpdateProductInput extends CommonProductInput {
  @field()
  readonly _key: string;
}
6 replies