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

Make raw great #1164

Closed
jasonkuhrt opened this issue Oct 3, 2024 · 2 comments · Fixed by #1165
Closed

Make raw great #1164

jasonkuhrt opened this issue Oct 3, 2024 · 2 comments · Fixed by #1165

Comments

@jasonkuhrt
Copy link
Member

Perceived Problem

  • raw client feels unresolved, not fun enough to use.

Ideas / Proposed Solution(s)

Summary benefits of following idea(s) over current raw approach:

  1. String and DocumentNode are two separate APIs. Consolidating them is easier to learn and use if done right.
  2. Choice between string and document node always left to user. But internally, Graffle could make better
    automatic decisions. For example if there are schema-driven features present, then there would be no need
    to parse the string into a DocumentNode. Don't require users think about this to get best performance for
    their chosen feature set.
  3. Separating variables and operation name from the document parameter allows us to leverage a template literal
    approach which is more succinct to read and it brings some other benefits, see following points.
  4. Putting gql method on chain permits IDE tooling support without having to deal with importing gql from graffle
    or any other helper package/module. So easier to use.
  5. The type inference is a PITA using the current object approach. I've struggled to get the variables key to
    depend on the state of the passed in typed document node/string/query. Moving the variables and operation name
    to another method makes the typing much easier to pull off. Functionally, I have been unable to get the result
    set to infer with types computed (aka. simplified). While correct, they are unreadable.
  6. The idea of extending gql method to root type namespaces on the chaining api seems to open up a really nice
    convenience method. The template literal allows us to have arguments passed in-context. It doesn't allow one
    operation argument to apply in two places but that's ok, its just for simple cases. Its sugar. Nice sugar.
    Without the template literal succinctness this idea wouldn't be compelling.

Document Level template literal with variables

const data = await graffle
  .gql`
    query pokemonByName ($Name: String!) {
      pokemonByName (name: $Name) {
        name
        continent {
          name
        }
      }
    }
  `
  .run({
    name: `Pikachu`,
  })

Document Level template literal with variables, operation name

const data = await graffle
  .gql`
    query pokemonByName ($Name: String!) {
      pokemonByName (name: $Name) {
        name
        continent {
          name
        }
      }
    }
  `
  .run(`pokemonByName`, {
    name: `Pikachu`,
  })

Passing in a type variable to have the arguments typed and results inferred.

const data = await graffle
  .gql<QueryPokemonByName>`
    query pokemonByName ($Name: String!) {
      pokemonByName (name: $Name) {
        name
        continent {
          name
        }
      }
    }
  `
  .run({
    name: `Pikachu`,
  })

type QueryPokemonByName = TypedQueryDocumentNode<
  {
    pokemonByName: {
      id: string
      name: string
      hp: number
      attack: number
      defense: number
      trainer: { name: string }
    }
  },
  { name: string }
>

Using a prepared DocumentNode instance.

The gql function can continue to be used as a way to create documents.

const document = gql`
  query pokemonByName ($Name: String!) {
    pokemonByName (name: $Name) {
      name
      continent {
        name
      }
    }
  }
`

const data = await graffle
  .gql(document)
  .run({ name: `Pikachu` })

Access the constructed DocumentNode instance

const document = graffle.gql`
  query pokemonByName ($Name: String!) {
    pokemonByName (name: $Name) {
      name
      continent {
        name
      }
    }
  }
`.document

Sugar: Root Type Level template literal. Interpolates variables into GraphQL document

  • Pro: no need for additional methods/parameters to think about for arguments or operation name
  • Con: IDE tooling likely to not understand that the query operation declaration is elided.variables.
const data = await graffle.query.gql`
  pokemonByName (name: ${`Pikachu`}) {
    name
    continent {
      name
    }
  }
`
@P4sca1
Copy link

P4sca1 commented Oct 5, 2024

Is it possible to pass in TypedDocumentNode from https://github.com/dotansimha/graphql-typed-document-node? Im thinking about using the raw client with generated typed document nodes to avoid the client bundle overhead from the generated graffle client. Typed document nodes could likely be tree-shaken per page so that each page only bundles the graphql documents needed instead of a full-blown client.

@jasonkuhrt
Copy link
Member Author

@P4sca1 yup that will be supported. The PR already achieved that. I just have to tidy everything up. Won't be long, today or tomorrow.

@jasonkuhrt jasonkuhrt unpinned this issue Oct 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants