Generate mutation hooks from graphql types

I’ve been working on a script to help me keep up with a side project.

The script generates hooks for all mutations declared in my graphql schemas. It types each hooks using the types in graphql, so that this:

export const schema = gql`
  type Tag {
    id: Int!
    label: String!
    projects: [Project]
    tasks: [Task]
  }

  type Query {
    tags: [Tag!]! @requireAuth
    tag(id: Int!): Tag @requireAuth
  }

  input CreateTagInput {
    label: String!
  }

  input UpdateTagInput {
    label: String
  }

  type Mutation {
    createTag(input: CreateTagInput!): Tag! @requireAuth
    updateTag(id: Int!, input: UpdateTagInput!): Tag! @requireAuth
    deleteTag(id: Int!): Tag! @requireAuth
  }
`

generates this:

// create
import type { Tag, MutationcreateTagArgs } from 'types/graphql'

import { useMutation, TypedDocumentNode } from '@redwoodjs/web'

const MUTATION_CREATETAG: TypedDocumentNode<Tag, MutationcreateTagArgs> = gql`
  mutation MUTATION_CREATETAG($input: CreateTagInput!) {
    createTag(input: $input) {
      id
    }
  }
`

/**
 * @signature Y3JlYXRlVGFnL011dGF0aW9uY3JlYXRlVGFnQXJncy9pbnB1dChsYWJlbCkvVGFn
 * @param options
 * @returns
 */
export function useCreateTag(
  options: GraphQLMutationHookOptions<Tag, MutationcreateTagArgs> = {}
) {
  const [mutation, { loading, error, data }] = useMutation(MUTATION_CREATETAG, {
    onCompleted(_data: Tag) {
      console.log('Success')
    },
    ...options,
  })

  return { mutation, request: { loading, error, data } }
}
// update
import type { Tag, MutationupdateTagArgs } from 'types/graphql'

import { useMutation, TypedDocumentNode } from '@redwoodjs/web'

const MUTATION_UPDATETAG: TypedDocumentNode<Tag, MutationupdateTagArgs> = gql`
  mutation MUTATION_UPDATETAG($id: Int!, $input: UpdateTagInput!) {
    updateTag(id: $id, input: $input) {
      id
    }
  }
`

/**
 * @signature dXBkYXRlVGFnL011dGF0aW9udXBkYXRlVGFnQXJncy9pbnB1dChsYWJlbCkvVGFn
 * @param options
 * @returns
 */
export function useUpdateTag(
  options: GraphQLMutationHookOptions<Tag, MutationupdateTagArgs> = {}
) {
  const [mutation, { loading, error, data }] = useMutation(MUTATION_UPDATETAG, {
    onCompleted(_data: Tag) {
      console.log('Success')
    },
    ...options,
  })

  return { mutation, request: { loading, error, data } }
}
// delete
import type { Tag, MutationdeleteTagArgs } from 'types/graphql'

import { useMutation, TypedDocumentNode } from '@redwoodjs/web'

const MUTATION_DELETETAG: TypedDocumentNode<Tag, MutationdeleteTagArgs> = gql`
  mutation MUTATION_DELETETAG($id: Int!) {
    deleteTag(id: $id) {
      id
    }
  }
`

/**
 * @signature ZGVsZXRlVGFnL011dGF0aW9uZGVsZXRlVGFnQXJncy9UYWc=
 * @param options
 * @returns
 */
export function useDeleteTag(
  options: GraphQLMutationHookOptions<Tag, MutationdeleteTagArgs> = {}
) {
  const [mutation, { loading, error, data }] = useMutation(MUTATION_DELETETAG, {
    onCompleted(_data: Tag) {
      console.log('Success')
    },
    ...options,
  })

  return { mutation, request: { loading, error, data } }
}

My side project has 42 operations declared, a lot of them are scattered in files here or there, random components, overcomplicated hooks that’ll make your coffee and whatever else you could imagine.
This mess makes my side project harder to maintain on my own while having a busy life, hence the idea of working on my own generating script.

I’m using jscodeshift to create the files and I’ve structured the script so it can keep track of your schema:

  • by adding missing hooks (eg: you need a createFriend mutation)
  • by removing obsolete hooks (eg: you no longer need a createFriend mutation)
  • by telling you when a mutation’s signature doesn’t match anymore the file you have (eg: createFriend mutation now only accepts female friends, contrary to a previous version which was less eager to discriminate)

Also, the script lints all the files and lets you use your own codemods to create your templates.

I’m close enough to something usable in a normal workflow, however I’d like to know if this can be pushed further.
It would be of tremendous help if my esteemed readers would answer the following questions:

  • Do you know and maybe use other tools that perform the same function?
  • Would you like to have this when working on your redwoodjs projects?
  • Would you like to have this when working with other frameworks using graphql?

I’m ready to put more efforts in this second side project, as long as there could be interest and use by the community.

Thanks for reading and happy coding!

2 Likes