-
Notifications
You must be signed in to change notification settings - Fork 14
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
Support positional resolver arguments #23
Comments
After some discussion in other issues (#21 (comment)) and on Discord, I think this is probably not great to use positional arguments. GraphQL arguments are named/keyed so, while the object syntax is awkward in JS, I think it's best to stick with it since it more semantically matches GraphQL. At some point in the future we could come back to this if we think the ergonomic value outweighs modeling GraphQL semantics accurately. |
Another point in favor of this approach is the ergonomics of default values, especially when combined with descriptions. /** @gqlField */
export async function searchItems(
_: Query,
{
query,
first = 100,
}: {
query: string;
/** Must be between 100 and 10,000 */
first?: Int;
}
): Promise<SearchItemsConnection> {
// ...
} Is much more painful than: /** @gqlField */
export async function searchItems(
_: Query,
query: string,
/** Must be between 100 and 10,000 */
first?: Int = 10
): Promise<SearchItemsConnection> {
// ...
} |
Another argument in favor of this approach came up in Discord and I figured I'd document it here: One appealing pattern which is uniquely enabled by implementation first solutions like Grats is that you can reuse your model types as the skeleton of your GraphQL Schema. For example, if you had a user model: class User {
name: string;
greet(salutation: string): string;
} And you wanted to expose it in the graph: /** @gqlType */
class User {
/** @gqlField */
name: string;
/** @gqlField */
greet(salutation: string): string {
return `${salutation} ${this.name}`
};
} Today you'd either need to add a new field for greet that accepted its args as an object, or change the signature of the existing greet field to be less ergonomic for internal use. However, if we supported positional arguments, you could expose it as written without needing to duplicate it or modify it. |
As I think more about this, one of the key value Grats unlocks, is to expose existing methods as fields. I think enabling that type of developer experience might bring this feature back into the set of things we should consider doing. |
I took a stab at migrating a TypeGraphQL app to Grats this evening, and found that not having support for positional args made it rather difficult. Ideally, one could just:
Right now that's not possible due to Grats requiring object shaped args. |
GraphQL JS expects GraphQL field arguments to be passed to the resolver as a single
args
object where each argument is a named property. This makes sense in a world where your executor does not know anything about the implementation of your resolvers, but in Grats I think we can offer a more ergonomic alternative: positional arguments.So, instead of:
We could support the simpler:
This becomes especially nice when you want to have descriptions or
@deprecated
on your args:Implementation
At extraction time Grats could annotate the fields with directives defining which field name maps to which position. That mapping could then be implemented using the same type of resolver wrapper we use for
@methodName
.Context
One reason not to use positional arguments is that it interferes with your non-GraphQL arguments like context and the extra metadata argument. However, if Grats knew which type was your context type (for example via a
@gqlContext
tag), it could just know which position you were expecting your context in, and pass it in this position using a similar mapping strategy:v.s the more verbose
Now even the context object does not need to be defined at a fixed postion. Maybe you prefer getting your context first?
(On the other hand, maybe having a strong convention around context going after all GraphQL arguments is better for clarity in the code base. In which case that last option might be a bridge too far.)
The text was updated successfully, but these errors were encountered: