Skip to content
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

Validate that all context types match #29

Merged
merged 5 commits into from
Nov 3, 2023
Merged

Conversation

captbaritone
Copy link
Owner

Fixes #21. Directly implements what @mandx suggested in #21 (comment).

An alternative /** @gqlContext */ approach is explored in #24.

Copy link

netlify bot commented Nov 3, 2023

Deploy Preview for grats ready!

Name Link
🔨 Latest commit 8ee1d65
🔍 Latest deploy log https://app.netlify.com/sites/grats/deploys/6545788d5d5dde00088a523d
😎 Deploy Preview https://deploy-preview-29--grats.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@@ -50,7 +50,6 @@
- [ ] Improve playground
- Could we actually evaluate the resolvers? Maybe in a worker?
- Could we hook up GraphiQL 2?
- [ ] Can we ensure the context and ast arguments of resolvers are correct?
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe premature to add this since we don't yet typecheck the info argument.

@@ -980,7 +985,7 @@ export class Extractor {
} else if (node.kind === ts.SyntaxKind.FalseKeyword) {
return this.gql.boolean(node, false);
} else if (ts.isObjectLiteralExpression(node)) {
return this.cellectObjectLiteral(node);
return this.collectObjectLiteral(node);
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated typo fix.

Copy link
Contributor

@mandx mandx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very exciting this change! I was thinking (maybe you though this too) Grats could also support the @gqlContext docblock tag, so when present, all ctx arguments' type must resolve to that, otherwise, use this checking strategy as fallback.

-----------------
OUTPUT
-----------------
src/tests/fixtures/resolver_context/MultipleContextValuesUsed.invalid.ts:16:34 - error: Context argument's type does not match. Grats expects all resolvers that read the context argument to use the same type for that argument. Did you use the incorrect type in one of your resolvers?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should explain that Grats needs the exact same type reference (instead of structurally equivalent types) because it doesn't perform typechecking on the ctx arguments' type. Any user with TS experience will look at GratsContext and AlsoGratsContext and think "but, they are the same!" but "same" in this context means different things when Grats is checking the schema and when TS checks the code.

-----------------
src/tests/fixtures/resolver_context/ContextValueTypedAsString.invalid.ts:4:30 - error: Expected context parameter's type to be a type reference Grats validates that your context parameter is type-safe by checking all context values reference the same type declaration.

4 greeting(args: never, ctx: string): string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is not supporting string intentional? Or is it because some technical limitation?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technical limitation because we are tracking the definition of the type, and primitives and literals won't work.

-----------------
src/tests/fixtures/resolver_context/ContextValueTypedAsNever.ts:4:30 - error: Expected context parameter's type to be a type reference Grats validates that your context parameter is type-safe by checking all context values reference the same type declaration.

4 greeting(args: never, ctx: never): string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it not possible to allow unknown as the type for ctx?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could, just haven't added it yet! Unclear if it's needed though. I guess if you need to access the info argument after the context value and you don't actually ever use the context value?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's one use case. It would be a just escape hatch, in case we need to add the context argument (for whatever reason) but we don't want to deal with typing the context right now.

However, if it's easy to add, we could not add it now, and wait for (less theoretical, more practical) reasons to add it and make a better decision then.

@captbaritone
Copy link
Owner Author

Very exciting this change! I was thinking (maybe you though this too) Grats could also support the @gqlContext docblock tag, so when present, all ctx arguments' type must resolve to that, otherwise, use this checking strategy as fallback.

Yeah, I had a similar thought but more sequential than options. We can start here, and if we end up needing to actually know which value is the context value (say for positional arguments) we could layer on the @gqlContext tag as a new requirement. It would be a breaking change, but it would just mean adding a single tag to your single context type definition.

@mandx
Copy link
Contributor

mandx commented Nov 3, 2023

Very exciting this change! I was thinking (maybe you though this too) Grats could also support the @gqlContext docblock tag, so when present, all ctx arguments' type must resolve to that, otherwise, use this checking strategy as fallback.

Yeah, I had a similar thought but more sequential than options. We can start here, and if we end up needing to actually know which value is the context value (say for positional arguments) we could layer on the @gqlContext tag as a new requirement. It would be a breaking change, but it would just mean adding a single tag to your single context type definition.

I think all modes are valid, it just adds some complexity to the checking code:

  • If a positional arguments are found, then @gqlContext is required to be defined, and all present context args must reference that type.
  • If no positional args are found, but @gqlContext is defined, then all present context args must reference that type.
  • If no positional args are found, and @gqlContext is not defined, then just check that all present context args must reference that the same type, whatever that is.

I can see this working great, as long as if a check fails the error message is descriptive enough to explain what and why, and provide actions or suggestions.

@@ -161,11 +161,11 @@ export function typeNameDoesNotMatchExpected(expected: string) {
}

export function argumentParamIsMissingType() {
return "Expected GraphQL field arguments to have a TypeScript type. If there are no arguments, you can use `args: never`.";
return "Expected GraphQL field arguments to have a TypeScript type. If there are no arguments, you can use `args: unknown`.";
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check/guidance was wrong before, but I'm fixing it here. Should have been unknown for this use case not never.

@@ -22,7 +22,7 @@ const config = {
projectName: "grats", // Usually your repo name.

onBrokenLinks: "throw",
onBrokenMarkdownLinks: "warn",
onBrokenMarkdownLinks: "throw",
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Errors were turning up in CI but not local dev. This fixes that.

@captbaritone captbaritone merged commit 6a72239 into main Nov 3, 2023
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow Grats to validate context values
2 participants