{"id":15975747,"url":"https://github.com/Snowflyt/graphql-intuitive-request","last_synced_at":"2025-10-20T15:31:33.974Z","repository":{"id":110778852,"uuid":"609429293","full_name":"Snowflyt/graphql-intuitive-request","owner":"Snowflyt","description":"Intuitive and (more importantly) TS-friendly GraphQL client for queries, mutations and subscriptions","archived":false,"fork":false,"pushed_at":"2024-03-23T18:51:29.000Z","size":569,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-30T08:26:10.413Z","etag":null,"topics":["graphql","graphql-client","graphql-request","graphql-subscriptions","graphql-ws","typesafe","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/graphql-intuitive-request","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Snowflyt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-03-04T06:19:15.000Z","updated_at":"2024-09-27T12:29:31.000Z","dependencies_parsed_at":"2024-03-23T19:45:12.156Z","dependency_job_id":null,"html_url":"https://github.com/Snowflyt/graphql-intuitive-request","commit_stats":null,"previous_names":["snowflyt/graphql-intuitive-request","snowfly-t/graphql-intuitive-request"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snowflyt%2Fgraphql-intuitive-request","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snowflyt%2Fgraphql-intuitive-request/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snowflyt%2Fgraphql-intuitive-request/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snowflyt%2Fgraphql-intuitive-request/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Snowflyt","download_url":"https://codeload.github.com/Snowflyt/graphql-intuitive-request/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237358346,"owners_count":19297058,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["graphql","graphql-client","graphql-request","graphql-subscriptions","graphql-ws","typesafe","typescript"],"created_at":"2024-10-07T22:04:53.095Z","updated_at":"2025-10-20T15:31:28.617Z","avatar_url":"https://github.com/Snowflyt.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# graphql-intuitive-request\n\nIntuitive and (more importantly) TS-friendly GraphQL client for queries, mutations and subscriptions\n\n## Overview\n\ngraphql-intuitive-request provides an **intuitive** and **TS-friendly** way to write GraphQL queries, mutations and subscriptions(supports only graphql-ws) **without using string literals**, and provides **exact** return types inference.\n\n### Example\n\n```typescript\nimport { createClient, enumOf } from 'graphql-intuitive-request';\n\nconst { mutation, query } = createClient('https://example.com/graphql').withSchema({\n  User: {\n    id: 'Int!',\n    username: 'String!',\n    email: 'String',\n    posts: [{ 'first?': 'Int!' }, '[Post!]!'], // Field with arguments\n  },\n  Post: {\n    id: 'Int!',\n    status: 'PostStatus!',\n    title: 'String!',\n    content: 'String!',\n    author: 'User!',\n    coAuthors: '[User!]!',\n  },\n  PostStatus: enumOf('DRAFT', 'PUBLISHED', 'ARCHIVED'), // Enum type\n\n  Query: {\n    users: ['=\u003e', '[User!]!'],\n    post: [{ id: 'Int!' }, '=\u003e', 'Post'],\n  },\n  Mutation: {\n    removePost: [{ id: 'Int!' }, '=\u003e', 'Boolean!'],\n  },\n});\n\n/*\n * The type of `allUsers` is inferred as\n * Array\u003c{\n *   id: number;\n *   username: string;\n *   posts: Array\u003c{\n *     title: string;\n *     status: \"DRAFT\" | \"PUBLISHED\" | \"ARCHIVED\";\n *     coAuthors: Array\u003c{ id: number; username: string }\u003e;\n *   }\u003e;\n * }\u003e\n */\nconst allUsers = await query('users').select((user) =\u003e [\n  user.id,\n  user.username,\n  user.posts({ first: 10 }, (post) =\u003e [\n    post.title,\n    post.status,\n    post.coAuthors((author) =\u003e [author.id, author.username]),\n  ]),\n]);\n\n/*\n * The type of `post` is inferred as\n * {\n *   title: string;\n *   status: \"DRAFT\" | \"PUBLISHED\" | \"ARCHIVED\";\n *   content: string;\n *   author: { username: string };\n *   coAuthors: Array\u003c{ username: string }\u003e;\n * } | null\n */\nconst post = await query('post', { id: 1 }).select((post) =\u003e [\n  post.title,\n  post.status,\n  post.content,\n  post.author((author) =\u003e [author.username]),\n  post.coAuthors((author) =\u003e [author.username]),\n]);\nawait mutation('removePost').byId(1);\n// ... or use `.by` method and its variants\nconst post2 = await query('post')\n  .select((post) =\u003e [\n    post.title,\n    post.status,\n    post.content,\n    post.author((author) =\u003e [author.username]),\n    post.coAuthors((author) =\u003e [author.username]),\n  ])\n  .byId(1);\n```\n\nAs you can see, the return type of the “users” query is inferred as\n\n```typescript\nArray\u003c{\n  id: number;\n  username: string;\n  posts: Array\u003c{\n    title: string;\n    status: 'DRAFT' | 'PUBLISHED' | 'ARCHIVED';\n    coAuthors: Array\u003c{ id: number; username: string }\u003e;\n  }\u003e;\n}\u003e;\n```\n\nwhich is **exactly** what we want, not just a generic object like `User[]`!\n\n![Exact Type Inference with TypeScript](./docs/img/exact-type-inference.png)\n\nThe schema is equivalent to the following GraphQL schema:\n\n```graphql\ntype Query {\n  users: [User!]!\n  post(id: Int!): Post\n}\n\ntype User {\n  id: Int!\n  username: String!\n  email: String\n  posts(first: Int): [Post!]!\n}\n\ntype Post {\n  id: Int!\n  status: PostStatus!\n  title: String!\n  content: String!\n}\n\nenum PostStatus {\n  DRAFT\n  PUBLISHED\n  ARCHIVED\n}\n```\n\nThe syntax is almost the same as the one used in GraphQL:\n\n- Types are defined in the `withSchema` function.\n- Types are nullable by default, and you can use `!` to indicate that a type is non-nullable.\n- Wrapping a type in `[]` indicates that the type is a list.\n- You can use `enumOf` to define an enum type, and it will be inferred as a union type of string literals. Enum type declarations must be placed on the top level of the `withSchema` function—Just like in a GraphQL schema, enum types cannot be defined inside other types.\n- Queries, mutations and subscriptions are defined specially in `Query`, `Mutation` and `Subscription` fields of the `withSchema` function. The value of each field should be either of the following:\n  - `['=\u003e', 'ReturnType']` if the operation does not accept any input.\n  - `[{ /* ... */ }, '=\u003e', 'ReturnType']` if the operation accepts an input. In this case, the first element is an object representing the input type of the operation, and the third element is the return type of the operation.\n  - Especially, you can use `'void'` as the return type of a mutation if it does not return anything (e.g. A mutation that always returns `null` and you don't care about the return value).\n\nYou may notice that we actually define a circular reference between `User` and `Post` in the `withSchema` function. This is not a problem, because graphql-intuitive-request is smart enough to handle this case. However, when dealing with circular references, you should be careful to avoid infinite loops—graphql-intuitive-request supports selecting all fields of an object recursively (as will be shown later), and infinite loops may occur when selecting all fields of an object with circular references.\n\nThanks to the great magic of TypeScript's type system, you can be sure that the types you define are correct at compile time, and you will get an error if you define an invalid type. Such form of type definition is inspired by [ArkType](https://arktype.io/), a powerful TypeScript type parser and validator.\n\nSo now when you access fields that are not requested in the query, TypeScript will throw an error at compile time! You can be sure that you will not access a field that does not exist in the query at runtime.\n\n![TypeScript Compile Time Type Check](./docs/img/typescript-compile-time-type-check.png)\n\nAlso, now you get **intellisense** for the fields of the query, and you can **easily** add new fields to the query by making full use of TypeScript's type system! There's no need to use ESLint plugins to validate your GraphQL queries!\n\n![TypeScript Intellisense Support](./docs/img/typescript-intellisense.png)\n\n### Features\n\n- **Exact return types inference** for queries, mutations and subscriptions—if you query an entity with **specific** fields, then the return type will be an object with those fields, **not a generic object**.\n- **Intuitive** API made full use of TypeScript's type system—**no need** to write GraphQL queries in **string**s and use ESLint plugins to validate them, everything just in TypeScript!\n- Built on top of `graphql-request`, with support for `graphql-ws` **subscriptions**.\n\n## Installation\n\n```shell\nnpm install graphql-intuitive-request\n```\n\n**Note:** Requires TypeScript \u003e= 5.4\n\n\u003e [!TIP]\n\u003e\n\u003e Turn on `strictNullChecks` in your `tsconfig.json` to get the best experience. Otherwise, graphql-intuitive-request will not be able to infer some nullable fields correctly, and would just infer them as non-nullable ones.\n\n## Usage\n\n`graphql-intuitive-client` is very smart and flexible, along with full TypeScript support, so you can use it in many ways. The following examples are just some common use cases.\n\n```typescript\nconst { query, mutation } = createClient('https://example.com/graphql').withSchema({\n  /* ... */\n  Query: {\n    user: [{ id: 'Int!' }, '=\u003e', 'User'],\n    users: ['=\u003e', '[User!]!'],\n    /* ... */\n  },\n  Mutation: {\n    login: [{ input: 'LoginInput!' }, '=\u003e', 'LoginOutput!'],\n    logout: ['=\u003e', 'Boolean!'],\n    removeUser: [{ id: 'Int!' }, '=\u003e', 'Boolean!'],\n    /* ... */\n  },\n});\n\n// The normal way to execute operations\nconst user = await query('user')\n  //  ^?: { id: number; name: string; } | null\n  .select((user) =\u003e [user.id, user.name])\n  .by({ id: 1 });\n// Abbreviated syntax when the count of non-optional input fields is 1\n// Here, the only non-optional input field is `id`, so we can use `byId` instead of `by({ id: /* ... */ })`\n// In other cases, it may be `byUsername`, `byInput`, `byOptions`, etc.\nconst user = await query('user')\n  //  ^?: { id: number; name: string; } | null\n  .select((user) =\u003e [user.id, user.name])\n  .byId(1);\n// Alternatively, you can use the 2nd argument to pass the input instead of using `by` or its variants\nconst user = await query('user', { id: 1 }).select((user) =\u003e [user.id, user.name]);\n//    ^?: { id: number; name: string; } | null\n// You can omit `select` if you want to select all fields (it would also select nested ones recursively)\nconst user = await query('user').by({ id: 1 });\n//    ^?: User | null\nconst user = await query('user').byId(1);\n//    ^?: User | null\nconst user = await query('user', { id: 1 });\n//    ^?: User | null\n// The same is to `users`, you can see that it accepts no input, so there's no `by` method\nconst users = await query('users').select((user) =\u003e [user.id, user.name]);\n//    ^?: Array\u003c{ id: number; name: string; }\u003e\n// Similarly, you can omit `select` if you want to select all fields\nconst users = await query('users');\n//    ^?: User[]\n// What about queries or mutations that do not return an object? As you can see, now there's no `select` method\nconst isUserRemoved = await mutation('removeUser').byId(1);\n//    ^?: boolean\nconst isUserRemoved = await mutation('removeUser', { id: 1 });\n//    ^?: boolean\nconst isLoggedOut = await mutation('logout');\n//    ^?: boolean\n\n// Subscriptions are also supported, but only subscriptions using `graphql-ws` protocol are supported\nconst { mutation, subscription } = createClient('https://example.com/graphql')\n  .withWebSocketClient({ url: 'ws://example.com/graphql' })\n  .withSchema({\n    /* ... */\n    Subscription: {\n      commentAdded: [{ postId: 'Int!' }, '=\u003e', 'Comment!'],\n    },\n  });\n\nconst onCommentAddedSubscription = subscription('commentAdded')\n  .select((comment) =\u003e [comment.id, comment.content])\n  .byPostId(1);\nconst unsubscribe = onCommentAddedSubscription.subscribe((comment) =\u003e {\n  console.log(comment.id, comment.content);\n});\nsetTimeout(async () =\u003e {\n  await mutation('addComment').by({ postId: 1, content: 'Hello world!' });\n  unsubscribe();\n}, 1000);\n```\n\nFor more details, you can check [the relevant test file](./test/client.spec.ts).\n\n### Query field with arguments\n\ngraphql-intuitive-request supports querying fields with arguments. Say you have the following GraphQL schema:\n\n```graphql\ntype Query {\n  user(id: Int!): User\n}\n\ntype User {\n  id: Int!\n  name: String!\n  posts(status: PostStatus): [Post!]!\n}\n\nenum PostStatus {\n  DRAFT\n  PUBLISHED\n  ARCHIVED\n}\n\ntype Post {\n  id: Int!\n  title: String!\n  content: String!\n}\n```\n\nHow to represent `posts(status: PostStatus)` in the `withSchema` function? You can represent such a field with arguments as a 2-element tuple, where the first element is an object representing the input type of the field, and the second element is the return type of the field.\n\n```typescript\nimport { createClient, enumOf } from 'graphql-intuitive-request';\n\nconst { query } = createClient('https://example.com/graphql').withSchema({\n  User: {\n    id: 'Int!',\n    name: 'String!',\n    posts: [{ status: 'PostStatus' }, '[Post!]!'],\n  },\n  Post: {\n    id: 'Int!',\n    title: 'String!',\n    content: 'String!',\n  },\n  PostStatus: enumOf('DRAFT', 'PUBLISHED', 'ARCHIVED'),\n\n  Query: {\n    user: [{ id: 'Int!' }, '=\u003e', 'User'],\n  },\n});\n```\n\nNote that we use `[{ status: 'PostStatus' }, '[Post!]!']` instead of `['{ status: PostStatus }', '=\u003e', '[Post!]!']` (which is used in operation definitions like `Query`). This is to make operation definitions more concise and readable.\n\nThen you can query the `posts` field like this:\n\n```typescript\nconst user = await query('user', { id: 1 }).select((user) =\u003e [\n  user.id,\n  user.name,\n  user.posts({ status: 'PUBLISHED' }, (post) =\u003e [post.id, post.title]),\n]);\n```\n\nThis is equivalent to the following GraphQL query:\n\n```graphql\nquery user($id: Int!, $postStatus: PostStatus) {\n  user(id: $id) {\n    id\n    name\n    posts(status: $postStatus) {\n      id\n      title\n    }\n  }\n}\n```\n\n...with the following variables:\n\n```json\n{\n  \"id\": 1,\n  \"postStatus\": \"PUBLISHED\"\n}\n```\n\nSince all arguments of `posts` are optional, you can still query the `posts` field without arguments:\n\n```typescript\nconst user = await query('user', { id: 1 }).select((user) =\u003e [\n  user.id,\n  user.name,\n  user.posts((post) =\u003e [post.id, post.title]),\n]);\n```\n\nWhether you can omit arguments or not is validated at compile time, so you can be sure that you will not forget to pass required arguments at runtime.\n\n### Use scalars to transform values\n\nGraphQL provides the ability to define custom scalar types, which should be transformed to a specific type in the client. For example, you can define a `DateTime` scalar type in the GraphQL schema, and you want to transform it to a `Date` object in the client.\n\n```graphql\nscalar DateTime\n\ntype User {\n  id: Int!\n  name: String!\n  createdAt: DateTime!\n}\n```\n\nTo define a scalar type in the `withSchema` function, you can use the `scalar` function.\n\n```typescript\nimport { createClient, scalar } from 'graphql-intuitive-request';\n\nconst { mutation, query } = createClient('https://example.com/graphql').withSchema({\n  User: {\n    id: 'Int!',\n    name: 'String!',\n    createdAt: 'DateTime!',\n  },\n  CreateUserInput: {\n    name: 'String!',\n    createdAt: 'DateTime!',\n  },\n  DateTime: scalar\u003cDate\u003e()({\n    parse: (value) =\u003e new Date(value),\n    serialize: (value) =\u003e value.toISOString(),\n  }),\n\n  Query: {\n    user: [{ id: 'Int!' }, '=\u003e', 'User'],\n  },\n  Mutation: {\n    createUser: [{ input: 'CreateUserInput!' }, '=\u003e', 'User!'],\n  },\n});\n```\n\nThen when you query the `createdAt` field, the value will be transformed to a `Date` object. The same is true when you pass a `Date` object to the `createdAt` field in a mutation, the value will be serialized to a string.\n\n`GraphQLScalarType` from `graphql` package can also be used to replace the `scalar` function, so you can import other scalar types from packages like `graphql-scalars`.\n\n### Support for subscriptions\n\ngraphql-intuitive-request supports GraphQL subscriptions. You can use `client.subscription` to create a subscription. The usage is similar to `client.query` and `client.mutation`.\n\nNote that only subscriptions using `graphql-ws` protocol are supported. Due to the deprecated nature of `subscriptions-transport-ws`, we do not plan to support it in the future.\n\nIn order to connect to a `graphql-ws` subscription, you need to first use `client.withWebSocketClient` to attach a `graphql-ws` client to the graphql-intuitive-request client.\n\n```typescript\nimport { createClient } from 'graphql-intuitive-request';\n\nconst { mutation, subscription } = createClient('https://example.com/graphql', {\n  headers: {\n    Authorization: `Bearer \u003cyour_jwt_token\u003e`,\n  },\n})\n  .withWebSocketClient({\n    url: 'ws://example.com/graphql',\n    connectionParams: {\n      headers: {\n        Authorization: `Bearer \u003cyour_jwt_token\u003e`,\n      },\n    },\n  })\n  .withSchema(/* ... */);\n```\n\nThe parameters of `createClient().withWebSocketClient` are the same as the parameters of `createClient` function from `graphql-ws` package. You can refer to the [documentation of `graphql-ws`](https://the-guild.dev/graphql/ws/docs/interfaces/client.ClientOptions) for more details.\n\nThen you can use `client.subscription` to create a subscription.\n\n```typescript\nconst onCommentAddedSubscription = subscription('commentAdded', { postId: 1 }).select((comment) =\u003e [\n  comment.id,\n  comment.content,\n]);\n\nconst unsubscribe = onCommentAddedSubscription.subscribe((comment) =\u003e {\n  console.log(comment.id, comment.content);\n});\n\nsetTimeout(async () =\u003e {\n  await mutation('addComment').by({ postId: 1, content: 'Hello world!' });\n  unsubscribe();\n}, 1000);\n```\n\n_Note that you do not need to use `await` when creating a subscription or subscribe to a subscription._\n\nThen you can see the following output in the console after 1 second:\n\n```text\n1 Hello world!\n```\n\nThe `subscribe` method accepts three parameters:\n\n- subscriber: Necessary. The subscriber function. It will be called when a new value is emitted by the subscription. It accepts one parameter, which is the value emitted by the subscription.\n- onError: Optional. The error handler. It will be called when an error is emitted by the subscription. It accepts one parameter, which is the error emitted by the subscription.\n- onComplete: Optional. The completion handler. It will be called when the subscription is completed. It accepts no parameter.\n\n### Infer TypeScript types from GraphQL schema\n\nIt is annoying to define a type in GraphQL schema and repeat the same type in TypeScript. graphql-intuitive-request provides a convenient way to infer TypeScript types from the GraphQL schema.\n\n`schema` is a helper function to validate a GraphQL schema. It simply returns the schema itself and does nothing at runtime, but it is useful for TypeScript to ensure that the schema is valid.\n\n```typescript\nimport { createClient, enumOf, infer, schema } from 'graphql-intuitive-request';\n\nconst $ = schema({\n  User: {\n    id: 'Int!',\n    username: 'String!',\n    email: 'String',\n  },\n  Post: {\n    id: 'Int!',\n    status: 'PostStatus!',\n    title: 'String!',\n    content: 'String!',\n    author: 'User!',\n  },\n  PostStatus: enumOf('DRAFT', 'PUBLISHED', 'ARCHIVED'),\n\n  Query: {\n    users: ['=\u003e', '[User!]!'],\n    post: [{ id: 'Int!' }, '=\u003e', 'Post'],\n  },\n});\n\nexport const client = createClient('https://example.com/graphql').withSchema($);\n```\n\nAfter that, you can use the `infer` helper function to infer TypeScript types from the schema.\n\n```typescript\nconst $$ = infer($);\n\n/*\n * The type of `Post` is inferred as\n * Array\u003c{\n *   id: number;\n *   status: \"DRAFT\" | \"PUBLISHED\" | \"ARCHIVED\";\n *   title: string;\n *   content: string;\n *   author: { id: number; username: string; email: string | null };\n * }\u003e\n */\nexport type Post = typeof $$.Post;\n```\n\nAs you can see, you can use `typeof inferred.\u003cType\u003e` to get the inferred TypeScript type of a type in the schema. Like `schema`, `infer` also does nothing at runtime, it is only used to infer TypeScript types from the schema.\n\n### Create object selector to eliminate duplication\n\nIt is annoying to repeat the same object selector every time when you want to select some fields of an object. graphql-intuitive-request provides a convenient way to eliminate the duplication of object selector.\n\nFor example, similar code like this may often be found in a project:\n\n```typescript\nconst users = await query('users').select((user) =\u003e [\n  user.id,\n  user.name,\n  user.roles((role) =\u003e [\n    role.name,\n    role.description,\n    role.permissions((permission) =\u003e [permission.name]),\n  ]),\n]);\n\nconst currentUser = await query('currentUser').select((user) =\u003e [\n  user.id,\n  user.name,\n  user.roles((role) =\u003e [\n    role.name,\n    role.description,\n    role.permissions((permission) =\u003e [permission.name]),\n  ]),\n]);\n```\n\nApparently, you don't want to repeat selecting the same fields of `Role` and `Permission` every time. You can easily eliminate the duplication of object selector like this:\n\n```typescript\nimport { selectorBuilder } from 'graphql-intuitive-request';\n\nconst coreRoleFields = selectorBuilder\u003cRole\u003e().select((role) =\u003e [\n  role.name,\n  role.description,\n  role.permissions((permission) =\u003e [permission.name]),\n]);\n\nconst users = await query('users').select((user) =\u003e [\n  user.id,\n  user.name,\n  user.roles(coreRoleFields),\n]);\n\nconst currentUser = await query('currentUser').select((user) =\u003e [\n  user.id,\n  user.name,\n  user.roles(coreRoleFields),\n]);\n```\n\nThe type returned by `selectorBuilder` has some helper methods like `.infer` or `.inferAsList` to help you infer the TypeScript type of the selector. These methods do not actually exist at runtime, they are only used to help TypeScript infer the type of the selector.\n\n```typescript\n/*\n * The type of `CoreRole` is inferred as\n * {\n *   name: string;\n *   description: string | null;\n *   permissions: Array\u003c{ name: string }\u003e;\n * }\n */\ntype CoreRole = typeof coreRoleFields.infer;\n\n/*\n * The type of `CoreRoleList` is inferred as\n * Array\u003c{\n *   name: string;\n *   description: string | null;\n *   permissions: Array\u003c{ name: string }\u003e;\n * }\u003e\n */\ntype CoreRoleList = typeof coreRoleFields.inferAsList;\n```\n\n### Get query string\n\nIt is possible to get the query string of a query or mutation using similar syntax as the one used to create a query or mutation.\n\n```typescript\nimport {\n  queryString,\n  mutationString,\n  /* ... */\n} from 'graphql-intuitive-request';\n\nconst queryUserString = queryString('user')\n  .input({ id: 'ID!' })\n  .select\u003cUser\u003e((user) =\u003e [user.id, user.name])\n  .build();\n```\n\nIt is quite similar to the syntax used to create a query or mutation, but you should use `queryString` / `mutationString` / `subscriptionString` instead of `query` / `mutation` / `subscription`.\n\nAlso, we pass a generic parameter to the `select` method to indicate the return type of the query, mutation or subscription.\n\n### Convert promise to query string and query request body\n\nIt is also possible to convert a client's queries, mutations and subscriptions to query strings and query request bodies.\n\nFor example, you can convert a query to query string like this:\n\n```typescript\nconst queryString = query('users')\n  .select((user) =\u003e [user.id, user.name])\n  .toQueryString();\n```\n\nThe query string will be like this:\n\n```graphql\nquery users {\n  users {\n    id\n    name\n  }\n}\n```\n\nYou can also convert a query to request body like this:\n\n```typescript\nconst queryRequestBody = query('user')\n  .select((user) =\u003e [user.id, user.name])\n  .byId(1)\n  .toRequestBody();\n```\n\nThe request body will be an object like this:\n\n```javascript\n{\n  query: 'query user($id: Int!) {\\n  user(id: $id) {\\n    id\\n    name\\n  }\\n}',\n  variables: { id: 1 },\n}\n```\n\nYou should remember that we provide this functionality just for debugging purpose, so you should not use it in production. If you only want to get the query string, you should use `queryString`, `mutationString` or `subscriptionString` instead.\n\n### Work with graphql-request\n\ngraphql-intuitive-request is built on top of graphql-request, so you can use all the features of graphql-request with graphql-intuitive-request.\n\nYou can get the underlying `GraphQLClient` instance of graphql-request by calling the `getRequestClient()` method on the client instance.\n\n```typescript\nconst client = createClient('http://example.com/graphql').withSchema({\n  /* ... */\n});\nconst graphQLClient = client.getRequestClient();\n```\n\nYou can pass the configuration object of `graphql-request` as the 2nd parameter of the `createClient` function. For example, say you’re using JWT for authentication, you can pass the JWT token in the `headers` option.\n\n```typescript\nconst client = createClient('http://example.com/graphql', {\n  headers: {\n    Authorization: 'Bearer \u003cyour_jwt_token\u003e',\n  },\n}).withSchema({\n  /* ... */\n});\n```\n\n### Handle errors\n\nIt is worth noting graphql-intuitive-request still use the same error handling mechanism as graphql-request. You can handle errors by catching them. The type of the error is `ClientError` from `graphql-request`, and graphql-intuitive-request also re-exports it.\n\n```typescript\nimport { ClientError } from 'graphql-intuitive-request';\nimport { query } from './client';\n\ntry {\n  const user = await query('user', { id: 1 }).select((user) =\u003e [user.id, user.name]);\n  console.log(user);\n} catch (error) {\n  if (error instanceof ClientError) console.error(error.response.errors);\n  else console.error(error);\n}\n\n// ... or use `Promise.catch`\nvoid query('user')\n  .select((user) =\u003e [user.id, user.name])\n  .byId(1)\n  .catch((err: ClientError) =\u003e {\n    console.error(err.response.errors);\n  });\n```\n\n### Work with graphql-ws\n\nThe subscription feature of graphql-intuitive-request is built on top of graphql-ws, so you can use all the features of graphql-ws with graphql-intuitive-request.\n\nYou can get the client provided by graphql-ws by calling the `getWSClient()` method on the client instance.\n\n```typescript\nconst client = createClient('http://example.com/graphql')\n  .withWebSocketClient({\n    url: 'ws://example.com/graphql',\n  })\n  .withSchema({\n    /* ... */\n  });\nconst wsClient = client.getWSClient();\n```\n\n## Future Plans\n\nCheck [docs/future-plans.md](./docs/future-plans.md) for the future plans of graphql-intuitive-request.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSnowflyt%2Fgraphql-intuitive-request","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSnowflyt%2Fgraphql-intuitive-request","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSnowflyt%2Fgraphql-intuitive-request/lists"}