2

Let's say we have a bookshop and an author entity, to show the author their earnings stat, we want to check if the authenticated user is indeed the author themselves. So we have:

  @UseGuards(GqlAuthGuard)
  @ResolveField(() => [Eearning], { name: 'earnings' })
  async getEarnings(
    @Parent() author: Author,
    @GqlUser() user: User,
  ) {
    if (user.id !== author.id)
      throw new UnauthorizedException(
        'Each author can only view their own data',
      );
    // rest of the function implementation
  }

We could query this:

query {
  author(id: "2bd79-6d7f-76a332b06b") {
    earnings {
      sells
    }
  }
}

Now imagine we want to use a custom Guard instead of that if statement. Something like below:

@Injectable()
export class AutherGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const ctx = GqlExecutionContext.create(context);
    // const artistId = ?
  }
}

How can I access the id argument given to the author query when AutherGuard is used for the getEarnings handler?

2
  • If an can only see their own earnings then no need to pass the author's id into the query. Just use the current user's id. (I make it a point never to pass the current user's id from client to server as it's redundant and creates opportunities for impersonation) Commented Jan 30, 2023 at 20:10
  • I agree. But the problem is that author() receives an id argument for public info that are accessible to all users. (like author.books). If I use the current author's id and they have entered an id other than their id, I still want to show a proper error instead of just passively returning their data (rather than the data of the id they have entered) Commented Jan 31, 2023 at 9:19

1 Answer 1

1

Not sure how documented is that but the parent object can be accessed through the getRoot method:

const gqlContext = GqlExecutionContext.create(context);
const root = gqlContext.getRoot();
const authorId = root.id;

In fact, we have a helper function that we use like this:

export function getArgs(context: ExecutionContext): any {
  if (context.getType<GqlContextType>() === "graphql") {
    const gqlContext = GqlExecutionContext.create(context);
    return { ...gqlContext.getArgs(), $parent: gqlContext.getRoot() };
  } else if (context.getType() === "http") {
    return context.switchToHttp().getRequest().params;
  }
}

...
const args = getArgs(context);
const authorId = _.get(args, "$parent.id");
Sign up to request clarification or add additional context in comments.

1 Comment

Well, this solves my problem! However, we still don't have access to the parent arguments there. If the argument passed is not retrievable by the parent object, then there isn't a way to get that argument. (Besides parsing the GraphQL query string, though)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.