Search code examples
node.jstypescriptgraphqltypegraphql

How do you omit fields in TypegraphQL


Let's say we have the following User model. { id: ID, email: string, username: string }

Then I want to define 2 queries:

  1. Used by the owner to get their settings page so it contains sensitive information such as email (perhaps sin number)
  2. Used by other users to search for a user (by username) & we do NOT want to expose the email or sin number I have been researching the documentation & cannot find how to accomplish this. I was thinking to grab the info for the fields manually & parse it per query but that seems like an oversight.

UPDATE: Here is sort of what I am trying to do:

class User {
  @Field(
    () => ID
  )
  id: string;

  @Authorized("CURRENT_USER")
  @Field(
    {
      nullable: true
    }
  )
  email: string;

  @Field()
  username: string;
}

Resolver:

export default class UserResolver {
  @Authorized("CURRENT_USER")
  @Query(
    () => User
  )
  async user(@Arg('username', () => String) username: string) {
     // TODO: if username is current user then allow email
     // else do not allow email, (I need auth checker in here)
  }
}

Solution

  • If I understand your question correctly you should be able to use the Authorized decorator in TypegraphQL. With this solution you should be able to add it to the email field in your User model. This should also be able to work with the sid field as well

    Have a look here: https://typegraphql.com/docs/authorization.html

    For example your User model could look something like this:

    class User {
      @Field()
      id: ID;
    
      @Authorized("LOGGEDINUSER")
      @Field({nullable: true})
      email: string;
    
      @Field()
      username: string;
    }
    

    You will have to allow the email field to be nullable

    You will also need to define an authChecker, with this you can run your logic to check if the user is the owner of the data, therefore granting them access to the data.

    An authChecker can look something like this:

    export const customAuthChecker: AuthChecker<Context> = (
      { args, context, info, root },
      roles
    ) => {
      // roles is an array of string which contains the authorization required to access the current resource
      // this is specified in the @Authorized decorator
      if (roles.includes("LOGGEDINUSER")) {
        // here check if the user is actually logged in and if they are allowed to access the resource
        // return true if they are allowed to access the resource
      }
      return false;
    };
    

    You will also need to change your call to the buildSchema to include the custom authChecker and authMode. For example:

      const schema = await buildSchema({
        resolvers: [UserResolver],
        authChecker: customAuthChecker,
        authMode: "null",
      });
    

    Note this will still return an email field but instead of returning the actual email it will return null when the user does not meet the authentication requirements