I've created a tiny library that creates GraphQL query from TypeScript, without losing type information
Tags: javascript, typescript, graphql, node
Published: 2018-12-19 18:24:01

---
title: I've created a tiny library that creates GraphQL query from TypeScript, without losing type information
published: true
description: 
tags: javascript, typescript, graphql, nodejs
---

I created a tiny experimental library, `typed-graphqlify`.

https://github.com/acro5piano/typed-graphqlify

`typed-graphqlify` creates GraphQL query string from TypeScript's type definition-like file.
I would like to reduce pain to use TypeScript + GraphQL.

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103885/cce5a0fe-f3ed-cc6a-c217-420993388828.png)

# Motivation

We all know that GraphQL is so great and solves many problems that we have with REST API, like overfetching and underfetching. But developing a GraphQL API in TypeScript is sometimes a bit of pain. Why? Let's take a look at the example we usually have to make.

When we use GraphQL library such as Apollo, We have to define query and its interface like this:

```typescript
interface GetUserQueryData {
  getUser: {
    id: number
    name: string
    bankAccount: {
      id: number
      branch: string
    }
  }
}

const query = graphql(gql`
  query getUser {
    user {
      id
      name
      bankAccount {
        id
        branch
      }
    }
  }
`)

apolloClient.query<GetUserQueryData>(query).then(data => ...)
```

This is so painful.

The biggest problem is the redundancy in our codebase, which makes it difficult to keep things in sync. To add a new field to our entity, we have to care about both GraphQL and TypeScript interface. And type checking does not work if we do something wrong.

**typed-graphqlify** comes to address this issues, based on experience from over a dozen months of developing with GraphQL APIs in TypeScript. The main idea is to have only one source of truth by defining the schema using GraphQL-like object and a bit of helper class. Additional features including graphql-tag, or Fragment can be implemented by other tools like Apollo.

I know tools that convert GraphQL Schema to TypeScript like Apollo-CLI, graphql-code-generator, and graphqlgen.

However, it needs Schema update and optional query cannot be defined from actual query.
At least in my particular use case, `typed-graphqlify` is more useful.

# How to use

Install it:

```
yarn add typed-graphqlify
```

First, define GraphQL-like JS Object:

```typescript
import { graphqlify, types } from 'typed-graphqlify'

const getUserQuery = {
  getUser: {
    user: {
      __params: { id: 1 },
      id: types.number,
      name: types.string,
      bankAccount: {
        id: types.number,
        branch: types.optional.string,
      },
    },
  },
}
```

Note that we use our `types` helper to define types in the result.

Then, convert the JS Object to GraphQL (string) with `graphqlify`:

```typescript
const gqlString = graphqlify('query', getUserQuery)

console.log(gqlString)
// =>
//   query getUser {
//     user(id: 1) {
//       id
//       name
//       bankAccount {
//         id
//         branch
//       }
//     }
//   }
```

Finally, execute the GraphQL:

```typescript
import { executeGraphql } from 'some-graphql-request-library'

// We would like to type this!
const result: typeof getUser = await executeGraphql(gqlString)

// As we cast `result` to `typeof getUser`,
// Now, `result` type looks like this:
// interface result {
//   user: {
//     id: number
//     name: string
//     bankAccount: {
//       id: number
//       branch?: string
//     }
//   }
// }
```

# Features

- Nested Query
- Input variables, parameters
- Query and Mutation
- Optional types

# Exapmles

Basic Query

```graphql
query getUser {
  user {
    id
    name
  }
}
```

```typescript
graphqlify('query', {
  getUser: {
    user: {
      id: types.number,
      name: types.string,
    },
  },
})
```

Basic Mutation

```graphql
mutation updateUser($input: UserInput!) {
  updateUser(input: $input) {
    id
    name
  }
}
```

```typescript
graphqlify('mutation', {
  __params: { $input: 'UserInput!' },
  updateUser: {
    __params: { input: '$input' },
    id: types.number,
    name: types.string,
  },
})
```

For more examples and documentation, please take a look at github repo:  https://github.com/acro5piano/typed-graphqlify

# TODO

- [x] Optional support
- [ ] Enum support

# Thanks

Inspired by

- https://github.com/kadirahq/graphqlify
- https://github.com/19majkel94/type-graphql