apollographql / apollographql/apollo-tooling

codegen - typescript idea of improvement - generate the operation too

Open
#1,767 1 comment 1 reaction 0 assignees View on GitHub
🤖 component - codegen
Dominant language
TypeScript
Stars
3k
Forks
460
PR merge metrics
No merged PRs in 30d

Description

Hey,

I forked client:codegen and added to it another functionality for personal use. I'd like to share the concept here to receive some feedbacks and see if there is some interests for it (maybe do a pull request later too)

So I wanted codegen to generates types but also the query operations itself for reducing a bit the boilerplate, without separing the graphql code from the tsx file.

So the implemented idea is to keep a gql template in .tsx files but not assign it to any variable.

here is an example, lets say we have a MyComponent file with 2 graphql operations (`getBooks`,`setBookAsFavorite`) in it:

```tsx
//in './myComponent.tsx'
import { gql } from '@apollo/client'
import ql,{useQuery,useMutation} from './__generated__'

gql`
query getBooks {
...
}

mutation setBookAsFavorite($BookId: ID!) {
...
}
`

const myComponent = () => {
const {data} = useQuery(ql.getBooks);

const [setBookAsFavorite] = useMutation(ql.setBookAsFavorite);

return <>...;
}
```

here the plugin will detect the gql tag, and generate from it the folder `__generated__`, very similar to what codegen currently do, it will contains the interfaces types, but it will also contains the graphql operations.

**please note here the variables and the data returned by the useQuery and useMutation hooks are fully typed** without the need to precise its type in the Apollo hooks. This thanks to a small tricks presented in the detail.

Here are the details on how it works under the hood:
Click me

`__generated__` folder store all the operations defined in the gql template, but also a small 'util.ts' file, and an 'index.ts' file:

```
.
├── MyComponent.tsx
└── __generated__
├── getBooks.ts
├── index.ts
├── setBookAsFavorite.ts
└── util.ts
```

the content of util.ts:

```ts
//in './__generated__/util.ts'
import { DocumentNode } from "graphql";
import { useQuery as useQueryOriginal, QueryHookOptions } from '@apollo/client'

export interface ExtQuery extends DocumentNode {
}

export function useQuery (query:ExtQuery, opt?:QueryHookOptions) {
return useQueryOriginal(query,opt);
}
```
note here the useQuery hook is a simple binding of the original Apollo useQuery hook, but it now expect a `ExtQuery` interface, an extended version of Graphql DocumentNode interface (type returned by gql template), here, this type will store the data interface and the variables interface directly in it.

(please note I hidden useMutation hooks which is almost the same as the useQuery hooks)

content of the getBook generated files:
```ts
//in './__generated__/getBooks.ts'
import {ExtQuery} from './util'

// all generated typescripts interfaces by codegen
export interface getBooks { ... };
export interface getBooksVariables { ... };

export const getInfoSystem:ExtQuery = gql`
query getBooks($parentId:ID!) {
...
}
`
```

Like this, all your graphql operations are fully typed, without having to add any code.

----

Here is another example with 1 graphql fragment and 1 subscription operation added:

```tsx
//in './myComponent2.tsx'
import ql,{useQuery,useMutation,useSubscription} from './__generated__'

gql`

fragment BookInfo on Book {...}

query getBooks{
books {
...BookInfo
}
}

subscription watchUpdateBooks {
watchUpdateBooks {
mutationKind
book {
...BookInfo
}
}
}

mutation setBookAsFavorite($id: ID!){
...
}

`
// --------------------------------------------------------------

const myComponent2 = () => {
const {data,updateQuery} = useQuery(ql.getBooks);

useSubscription(ql.watchUpdateBooks, { onSubscriptionData:(data)=>{updateQuery(...)} })

const [setBookAsFavorite] = useMutation(ql.setBookAsFavorite);

return <>...;
}
```

In my opinion, having one gql template which act as a .graphql file, can improve readability.

do you see some pros/cons in using this method?
Do having a gql template without assigned variable isn't too weird?

One possible problem I see is that depending if you're using Create-React-App, next.js etc... I'm not sure the gql template with no variable assigned is always remove for production build (I didn't checked)

Thanks for reading.

Contributor guide

Open the contributing guide

Research direction

Start by reviewing the codegen plugin behavior described in the issue and the generated __generated__ files, including the proposed util.ts and index.ts entry points. Compare the gql templates in the .tsx examples with current codegen output and Apollo useQuery, useMutation, and useSubscription usage. Done would require an agreed design and clear implementation scope for generating typed operations.

Written by the indexing model from the issue text.

Assessment

Tech stack
graphql, typescript
Domain
developer-experience, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
18/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.