From aaa0e50092cdb2c142068166ecd19a76cca7aea4 Mon Sep 17 00:00:00 2001 From: Cheng Gu Date: Thu, 3 Apr 2025 18:02:41 +0800 Subject: [PATCH 1/6] Create getting_started.md --- getting_started.md | 131 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 getting_started.md diff --git a/getting_started.md b/getting_started.md new file mode 100644 index 0000000..30c9cf6 --- /dev/null +++ b/getting_started.md @@ -0,0 +1,131 @@ +# Getting Started with FetchQL + +FetchQL is a lightweight GraphQL client that works in both browser and Node.js environments. This guide will help you get started with FetchQL, covering installation, basic usage, and how to make your first GraphQL query. + +## Installation + +You can install FetchQL using npm: + +```bash +npm install fetchql +``` + +## Basic Usage + +To use FetchQL in your project, first import it: + +```javascript +import FetchQL from 'fetchql'; +``` + +Or, if you're using CommonJS: + +```javascript +const FetchQL = require('fetchql'); +``` + +## Creating a FetchQL Instance + +To create a new FetchQL instance, you need to provide the GraphQL server URL: + +```javascript +const query = new FetchQL({ + url: 'https://your-graphql-server.com/graphql' +}); +``` + +You can also pass additional options: + +```javascript +const query = new FetchQL({ + url: 'https://your-graphql-server.com/graphql', + headers: { + 'Authorization': 'Bearer your-token' + }, + onStart: (requestQueueLength) => { + console.log(`New request queue started. Queue length: ${requestQueueLength}`); + }, + onEnd: (requestQueueLength) => { + console.log(`Request queue finished. Queue length: ${requestQueueLength}`); + }, + omitEmptyVariables: true +}); +``` + +## Making Your First GraphQL Query + +To make a GraphQL query using FetchQL, use the `query()` method: + +```javascript +query.query({ + operationName: 'GetUser', + query: ` + query GetUser($id: ID!) { + user(id: $id) { + id + name + email + } + } + `, + variables: { + id: '123' + } +}) +.then(({ data, errors }) => { + if (errors) { + console.error('GraphQL errors:', errors); + } else { + console.log('User data:', data.user); + } +}) +.catch(error => { + console.error('Network error:', error); +}); +``` + +## Handling Enum Types + +FetchQL provides a convenient way to fetch enum types from your GraphQL schema: + +```javascript +query.getEnumTypes(['UserRole', 'PostStatus']) + .then(({ data }) => { + console.log('Enum types:', data); + }) + .catch(error => { + console.error('Error fetching enum types:', error); + }); +``` + +## Using Interceptors + +FetchQL supports interceptors for request and response handling: + +```javascript +const removeInterceptors = query.addInterceptors({ + request: (url, config) => { + // Modify url or config here + return [url, config]; + }, + response: (response) => { + // Modify the response object + return response; + } +}); + +// Later, if you want to remove the interceptors: +removeInterceptors(); +``` + +## Changing the GraphQL Server URL + +You can change the GraphQL server URL at any time: + +```javascript +query.setUrl('https://new-graphql-server.com/graphql'); +``` + +## Conclusion + +This guide covered the basics of using FetchQL in your project. For more advanced usage and a complete list of features, refer to the FetchQL documentation and API reference. \ No newline at end of file From 370a87a484c37725388a82823db2e5d53e534ac3 Mon Sep 17 00:00:00 2001 From: Cheng Gu Date: Thu, 3 Apr 2025 18:02:45 +0800 Subject: [PATCH 2/6] Create enum_types_usage.md --- enum_types_usage.md | 128 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 enum_types_usage.md diff --git a/enum_types_usage.md b/enum_types_usage.md new file mode 100644 index 0000000..74da238 --- /dev/null +++ b/enum_types_usage.md @@ -0,0 +1,128 @@ +# Using getEnumTypes in FetchQL + +This guide explains how to use the `getEnumTypes` method in FetchQL, including its purpose, how to call it, and how to work with the returned enum type information. + +## Purpose + +The `getEnumTypes` method allows you to retrieve information about enum types from your GraphQL server. This is particularly useful when you need to dynamically populate UI elements (such as dropdowns) with enum values, or when you need to validate input against a set of allowed enum values. + +## How to Call getEnumTypes + +To use the `getEnumTypes` method, you first need to create a FetchQL instance: + +```javascript +import FetchQL from 'fetchql'; + +const fetchQL = new FetchQL({ + url: 'https://your-graphql-server.com/graphql' +}); +``` + +Then, you can call the `getEnumTypes` method with an array of enum type names: + +```javascript +fetchQL.getEnumTypes(['EnumType1', 'EnumType2']) + .then(({ data, errors }) => { + if (errors) { + console.error('Errors:', errors); + } else { + console.log('Enum types:', data); + } + }) + .catch(error => { + console.error('Error fetching enum types:', error); + }); +``` + +## Working with Returned Enum Type Information + +The `getEnumTypes` method returns a Promise that resolves to an object containing the requested enum type information. Here's an example of what the returned data might look like: + +```javascript +{ + EnumType1: { + name: 'EnumType1', + kind: 'ENUM', + description: 'Description of EnumType1', + enumValues: [ + { + name: 'VALUE1', + description: 'Description of VALUE1' + }, + { + name: 'VALUE2', + description: 'Description of VALUE2' + } + ] + }, + EnumType2: { + // ... similar structure for EnumType2 + } +} +``` + +You can use this information in various ways: + +1. Populating UI elements: + +```javascript +function populateDropdown(enumType) { + const dropdown = document.getElementById('myDropdown'); + enumType.enumValues.forEach(value => { + const option = document.createElement('option'); + option.value = value.name; + option.textContent = value.description || value.name; + dropdown.appendChild(option); + }); +} + +fetchQL.getEnumTypes(['MyEnumType']) + .then(({ data }) => { + populateDropdown(data.MyEnumType); + }); +``` + +2. Validating input: + +```javascript +function validateEnumInput(input, enumType) { + const validValues = enumType.enumValues.map(v => v.name); + return validValues.includes(input); +} + +fetchQL.getEnumTypes(['MyEnumType']) + .then(({ data }) => { + const isValid = validateEnumInput('SOME_VALUE', data.MyEnumType); + console.log('Input is valid:', isValid); + }); +``` + +## Caching + +The `getEnumTypes` method includes built-in caching. After the first query for a specific enum type, subsequent requests for the same enum type will be served from the cache, improving performance and reducing unnecessary network requests. + +## Error Handling + +When using `getEnumTypes`, it's important to handle potential errors: + +```javascript +fetchQL.getEnumTypes(['NonExistentEnum']) + .then(({ data, errors }) => { + if (errors) { + console.error('GraphQL errors:', errors); + } else if (!data) { + console.error('No data returned'); + } else { + console.log('Enum types:', data); + } + }) + .catch(error => { + console.error('Network or other error:', error); + }); +``` + +By properly handling errors, you can ensure your application gracefully manages situations where enum types might not be available or when network issues occur. + +## Conclusion + +The `getEnumTypes` method in FetchQL provides a convenient way to retrieve and work with enum type information from your GraphQL server. By leveraging this feature, you can create more dynamic and type-safe applications that adapt to changes in your GraphQL schema. \ No newline at end of file From 3a210de912633bd185c3d3a706f76649a9dbf0f9 Mon Sep 17 00:00:00 2001 From: Cheng Gu Date: Thu, 3 Apr 2025 18:02:48 +0800 Subject: [PATCH 3/6] Create error_handling.md --- error_handling.md | 145 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 error_handling.md diff --git a/error_handling.md b/error_handling.md new file mode 100644 index 0000000..c8d702f --- /dev/null +++ b/error_handling.md @@ -0,0 +1,145 @@ +# Error Handling in FetchQL + +FetchQL provides various ways to handle errors that may occur during GraphQL operations. This guide will cover how to catch and process GraphQL errors, network errors, and how to use the error information returned by the library. + +## Types of Errors + +When using FetchQL, you may encounter two main types of errors: + +1. GraphQL Errors: These are errors returned by the GraphQL server in the response. +2. Network Errors: These occur when there's a problem with the network request itself. + +## Handling GraphQL Errors + +GraphQL errors are returned in the `errors` array of the response object. These errors are typically related to the query execution on the server side. + +### Example of handling GraphQL errors: + +```javascript +const fetchQL = new FetchQL({ url: 'https://api.example.com/graphql' }); + +fetchQL.query({ + operationName: 'GetUser', + query: ` + query GetUser($id: ID!) { + user(id: $id) { + name + email + } + } + `, + variables: { id: '123' } +}) +.then(({ data, errors }) => { + if (errors) { + console.error('GraphQL Errors:', errors); + // Handle GraphQL errors + } else { + // Process the data + console.log('User data:', data.user); + } +}) +.catch(error => { + console.error('Network Error:', error); + // Handle network errors +}); +``` + +In this example, GraphQL errors are checked in the `then` block by examining the `errors` property of the response. + +## Handling Network Errors + +Network errors are caught in the `catch` block of the Promise chain. These can occur due to various reasons such as network connectivity issues, CORS problems, or server unavailability. + +### Example of handling network errors: + +```javascript +fetchQL.query({ + operationName: 'GetPosts', + query: ` + query GetPosts { + posts { + id + title + } + } + ` +}) +.then(({ data, errors }) => { + // Process successful response +}) +.catch(error => { + console.error('Network Error:', error); + // Handle network error (e.g., show error message to user) +}); +``` + +## Using FetchQL's Error Information + +FetchQL provides detailed error information in case of request failures. When a request fails due to a network error, FetchQL returns a custom error object with the following structure: + +```javascript +{ + errors: [{ + message: res.statusText, + stack: res, + }] +} +``` + +You can access this information in the `catch` block: + +```javascript +fetchQL.query({ + // ... query options +}) +.catch(error => { + if (error.errors && error.errors.length > 0) { + console.error('Error message:', error.errors[0].message); + console.error('Error details:', error.errors[0].stack); + } +}); +``` + +## Handling Empty or Null Data + +FetchQL also handles cases where the data returned is empty or null. In such cases, it will reject the promise: + +```javascript +fetchQL.query({ + // ... query options +}) +.then(({ data, errors }) => { + // This block will only be executed if data is not null and not empty +}) +.catch(errors => { + if (errors) { + console.error('Query returned null or empty data:', errors); + } +}); +``` + +## Using Interceptors for Error Handling + +FetchQL allows you to add interceptors that can be used for global error handling. This is particularly useful for handling common error scenarios across multiple queries. + +```javascript +const errorInterceptor = { + response: function (response) { + if (response.errors) { + // Log errors or perform any global error handling + console.error('GraphQL Errors:', response.errors); + } + return response; + }, + responseError: function (error) { + // Handle network errors + console.error('Network Error:', error); + return Promise.reject(error); + } +}; + +fetchQL.addInterceptors(errorInterceptor); +``` + +By implementing these error handling strategies, you can ensure that your application gracefully handles both GraphQL and network errors when using FetchQL. \ No newline at end of file From d037c37fe12492c11e3dc2691ba680063710aa28 Mon Sep 17 00:00:00 2001 From: Cheng Gu Date: Thu, 3 Apr 2025 18:02:49 +0800 Subject: [PATCH 4/6] Create api_reference.md --- api_reference.md | 209 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 api_reference.md diff --git a/api_reference.md b/api_reference.md new file mode 100644 index 0000000..18473fe --- /dev/null +++ b/api_reference.md @@ -0,0 +1,209 @@ +# FetchQL API Reference + +FetchQL is a GraphQL client built on top of the Fetch API. It provides an easy-to-use interface for making GraphQL queries and managing request interceptors. + +## Table of Contents + +1. [Constructor](#constructor) +2. [Methods](#methods) + - [query](#query) + - [getEnumTypes](#getenumtypes) + - [getUrl](#geturl) + - [setUrl](#seturl) + - [addInterceptors](#addinterceptors) + - [removeInterceptors](#removeinterceptors) + - [clearInterceptors](#clearinterceptors) + +## Constructor + +### `new FetchQL(options)` + +Creates a new FetchQL instance. + +#### Parameters + +- `options` (Object): + - `url` (String): The server address of GraphQL. + - `interceptors` (Object | Object[]): Optional. Request interceptors. + - `headers` (Object): Optional. Request headers. + - `onStart` (Function): Optional. Callback function when a new request queue starts. + - `onEnd` (Function): Optional. Callback function when a request queue finishes. + - `omitEmptyVariables` (Boolean): Optional. Remove null props (null or '') from the variables. Default is `false`. + - `requestOptions` (Object): Optional. Additional options for fetch requests. + +#### Example + +```javascript +const client = new FetchQL({ + url: 'https://api.example.com/graphql', + headers: { + 'Authorization': 'Bearer token123' + }, + omitEmptyVariables: true +}); +``` + +## Methods + +### query + +`query(options): Promise` + +Executes a GraphQL query. + +#### Parameters + +- `options` (Object): + - `operationName` (String): Name of the GraphQL operation. + - `query` (String): GraphQL query string. + - `variables` (Object): Optional. Variables for the query. + - `opts` (Object): Optional. Additional options. + - `omitEmptyVariables` (Boolean): Remove null props from variables. + - `requestOptions` (Object): Optional. Additional options for fetch request. + +#### Returns + +A Promise that resolves to a `FetchQLQueryResult` object containing `data` and optional `errors`. + +#### Example + +```javascript +client.query({ + operationName: 'GetUser', + query: ` + query GetUser($id: ID!) { + user(id: $id) { + id + name + email + } + } + `, + variables: { id: '123' } +}).then(result => { + console.log(result.data); +}).catch(error => { + console.error(error); +}); +``` + +### getEnumTypes + +`getEnumTypes(EnumNameList): Promise` + +Retrieves information about enum types. + +#### Parameters + +- `EnumNameList` (String[]): Array of enum names to fetch. + +#### Returns + +A Promise that resolves to a `FetchQLEnumResult` object containing enum information. + +#### Example + +```javascript +client.getEnumTypes(['UserRole', 'OrderStatus']).then(result => { + console.log(result.data); +}).catch(error => { + console.error(error); +}); +``` + +### getUrl + +`getUrl(): string` + +Gets the current server address. + +#### Returns + +The current GraphQL server URL. + +#### Example + +```javascript +const currentUrl = client.getUrl(); +console.log(currentUrl); +``` + +### setUrl + +`setUrl(url: string): void` + +Sets a new server address. + +#### Parameters + +- `url` (String): The new GraphQL server URL. + +#### Example + +```javascript +client.setUrl('https://new-api.example.com/graphql'); +``` + +### addInterceptors + +`addInterceptors(interceptors: FetchQLInterceptor | FetchQLInterceptor[]): () => void` + +Adds new interceptors to the FetchQL instance. + +#### Parameters + +- `interceptors` (Object | Object[]): Interceptor object(s) with optional methods: + - `request`: Function called before a request is sent. + - `requestError`: Function called when a request encounters an error. + - `response`: Function called after a response is received. + - `responseError`: Function called when a response encounters an error. + +#### Returns + +A function that, when called, removes the added interceptors. + +#### Example + +```javascript +const removeInterceptors = client.addInterceptors({ + request: (url, config) => { + console.log('Request intercepted:', url); + return [url, config]; + }, + response: (response) => { + console.log('Response intercepted:', response); + return response; + } +}); + +// Later, to remove the interceptors: +removeInterceptors(); +``` + +### removeInterceptors + +`removeInterceptors(indexes: number[]): void` + +Removes interceptors by their indexes. + +#### Parameters + +- `indexes` (number[]): Array of interceptor indexes to remove. + +#### Example + +```javascript +client.removeInterceptors([0, 2]); // Removes the first and third interceptors +``` + +### clearInterceptors + +`clearInterceptors(): void` + +Removes all interceptors. + +#### Example + +```javascript +client.clearInterceptors(); +``` \ No newline at end of file From e27b8046657869c844cb95de803aa22f7ab7aa72 Mon Sep 17 00:00:00 2001 From: Cheng Gu Date: Thu, 3 Apr 2025 18:02:50 +0800 Subject: [PATCH 5/6] Create best_practices.md --- best_practices.md | 148 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 best_practices.md diff --git a/best_practices.md b/best_practices.md new file mode 100644 index 0000000..c3fe61a --- /dev/null +++ b/best_practices.md @@ -0,0 +1,148 @@ +# Best Practices for Using FetchQL in Production + +This guide provides a comprehensive list of best practices for using FetchQL in production applications. By following these recommendations, you can optimize performance, enhance security, and improve the overall organization of your GraphQL queries. + +## Performance Optimization + +1. **Use Query Batching**: Combine multiple queries into a single request when possible to reduce network overhead. + + ```javascript + const fetchQL = new FetchQL({ url: 'https://api.example.com/graphql' }); + + fetchQL.query({ + operationName: 'BatchedQueries', + query: ` + query BatchedQueries { + users { id name } + posts { id title } + } + ` + }); + ``` + +2. **Implement Caching**: Utilize client-side caching to store frequently accessed data and reduce server load. + +3. **Optimize Query Complexity**: Avoid overfetching by requesting only the necessary fields in your queries. + +4. **Use Pagination**: For large datasets, implement pagination to limit the amount of data transferred in a single request. + + ```javascript + fetchQL.query({ + operationName: 'PaginatedPosts', + query: ` + query PaginatedPosts($page: Int, $pageSize: Int) { + posts(page: $page, pageSize: $pageSize) { + id + title + } + } + `, + variables: { page: 1, pageSize: 10 } + }); + ``` + +5. **Leverage Enum Caching**: FetchQL provides built-in caching for enum types. Use `getEnumTypes()` to fetch and cache enum information. + + ```javascript + fetchQL.getEnumTypes(['PostStatus', 'UserRole']) + .then(({ data }) => { + console.log('Cached enum types:', data); + }); + ``` + +## Security Considerations + +1. **Use HTTPS**: Always use HTTPS for your GraphQL endpoint to encrypt data in transit. + +2. **Implement Authentication**: Secure your GraphQL API with proper authentication mechanisms. + + ```javascript + const fetchQL = new FetchQL({ + url: 'https://api.example.com/graphql', + headers: { + Authorization: 'Bearer YOUR_AUTH_TOKEN' + } + }); + ``` + +3. **Sanitize User Input**: Validate and sanitize all user-provided input before including it in queries. + +4. **Set Request Timeouts**: Implement timeouts to prevent long-running queries from overwhelming your server. + + ```javascript + const fetchQL = new FetchQL({ + url: 'https://api.example.com/graphql', + requestOptions: { + timeout: 5000 // 5 seconds timeout + } + }); + ``` + +5. **Use Query Whitelisting**: Implement a query whitelist on the server to prevent arbitrary queries from being executed. + +## Query Organization + +1. **Modularize Queries**: Organize your queries into separate files or modules for better maintainability. + +2. **Use Fragment Composition**: Utilize fragments to compose reusable query parts and reduce duplication. + + ```javascript + const userFragment = ` + fragment UserDetails on User { + id + name + email + } + `; + + fetchQL.query({ + operationName: 'GetUser', + query: ` + ${userFragment} + query GetUser($id: ID!) { + user(id: $id) { + ...UserDetails + } + } + `, + variables: { id: 'user123' } + }); + ``` + +3. **Implement Error Handling**: Use FetchQL's error handling capabilities to gracefully manage query errors. + + ```javascript + fetchQL.query({ + operationName: 'GetUser', + query: '...', + variables: { id: 'user123' } + }).then(({ data, errors }) => { + if (errors) { + console.error('GraphQL Errors:', errors); + } else { + console.log('User data:', data); + } + }).catch(error => { + console.error('Network Error:', error); + }); + ``` + +4. **Use Named Operations**: Always provide operation names for better debugging and logging. + +5. **Implement Request Queue Management**: Utilize FetchQL's `onStart` and `onEnd` callbacks to manage request queues and implement loading indicators. + + ```javascript + const fetchQL = new FetchQL({ + url: 'https://api.example.com/graphql', + onStart: (queueLength) => { + console.log(`Request queue started. Length: ${queueLength}`); + showLoadingIndicator(); + }, + onEnd: (queueLength) => { + console.log(`Request queue finished. Length: ${queueLength}`); + hideLoadingIndicator(); + } + }); + ``` + +By following these best practices, you can ensure that your FetchQL implementation is efficient, secure, and well-organized in production environments. Remember to regularly review and update your practices as your application scales and new features are introduced. \ No newline at end of file From 3650ca17889e5fa079879b169a272db76a60a7b0 Mon Sep 17 00:00:00 2001 From: Cheng Gu Date: Thu, 3 Apr 2025 18:02:52 +0800 Subject: [PATCH 6/6] Create migrating_to_fetchql.md --- migrating_to_fetchql.md | 198 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 migrating_to_fetchql.md diff --git a/migrating_to_fetchql.md b/migrating_to_fetchql.md new file mode 100644 index 0000000..9eb18d6 --- /dev/null +++ b/migrating_to_fetchql.md @@ -0,0 +1,198 @@ +# Migrating to FetchQL + +FetchQL is a lightweight GraphQL client that works in both browser and Node.js environments. This guide will help you migrate from other GraphQL clients to FetchQL, highlighting its unique features and providing examples of how to refactor your existing code. + +## Why Choose FetchQL? + +FetchQL offers several advantages: + +- Lightweight and easy to use +- Built-in request interceptors +- Support for enum type queries with caching +- Request state callbacks +- Written in ES2015 with module support + +## Installation + +To get started with FetchQL, install it using npm: + +```bash +npm install fetchql +``` + +## Basic Usage + +Here's a basic example of how to use FetchQL: + +```javascript +import FetchQL from 'fetchql'; + +const client = new FetchQL({ + url: 'https://your-graphql-server.com/graphql' +}); + +client.query({ + operationName: 'GetUser', + query: ` + query GetUser($id: ID!) { + user(id: $id) { + id + name + email + } + } + `, + variables: { id: '123' } +}) +.then(({ data, errors }) => { + if (errors) { + console.error(errors); + } else { + console.log(data.user); + } +}); +``` + +## Migrating from Apollo Client + +If you're migrating from Apollo Client, here are some key differences and how to adapt your code: + +1. **Client Initialization** + + Apollo Client: + ```javascript + import { ApolloClient, InMemoryCache } from '@apollo/client'; + + const client = new ApolloClient({ + uri: 'https://your-graphql-server.com/graphql', + cache: new InMemoryCache() + }); + ``` + + FetchQL: + ```javascript + import FetchQL from 'fetchql'; + + const client = new FetchQL({ + url: 'https://your-graphql-server.com/graphql' + }); + ``` + +2. **Queries** + + Apollo Client: + ```javascript + client.query({ + query: gql` + query GetUser($id: ID!) { + user(id: $id) { + id + name + email + } + } + `, + variables: { id: '123' } + }) + .then(result => console.log(result.data.user)); + ``` + + FetchQL: + ```javascript + client.query({ + operationName: 'GetUser', + query: ` + query GetUser($id: ID!) { + user(id: $id) { + id + name + email + } + } + `, + variables: { id: '123' } + }) + .then(({ data }) => console.log(data.user)); + ``` + + Note: FetchQL requires an `operationName` to be specified. + +3. **Mutations** + + Mutations in FetchQL are handled the same way as queries. Just change the query string to a mutation: + + ```javascript + client.query({ + operationName: 'UpdateUser', + query: ` + mutation UpdateUser($id: ID!, $name: String!) { + updateUser(id: $id, name: $name) { + id + name + } + } + `, + variables: { id: '123', name: 'New Name' } + }) + .then(({ data }) => console.log(data.updateUser)); + ``` + +## Unique Features of FetchQL + +### 1. Interceptors + +FetchQL allows you to add interceptors to modify requests or responses: + +```javascript +const interceptor = { + request: function (url, config) { + // Modify the url or config here + return [url, config]; + }, + response: function (response) { + // Modify the response object + return response; + } +}; + +client.addInterceptors(interceptor); +``` + +### 2. Enum Type Queries + +FetchQL provides a method to easily fetch enum types: + +```javascript +client.getEnumTypes(['UserRole', 'PostStatus']) + .then(({ data }) => { + console.log(data.UserRole); + console.log(data.PostStatus); + }); +``` + +### 3. Request State Callbacks + +You can track the state of requests using callbacks: + +```javascript +const client = new FetchQL({ + url: 'https://your-graphql-server.com/graphql', + onStart: (queueLength) => console.log(`Request started. Queue length: ${queueLength}`), + onEnd: (queueLength) => console.log(`Request ended. Queue length: ${queueLength}`) +}); +``` + +### 4. Omitting Empty Variables + +FetchQL can automatically remove null or empty string variables: + +```javascript +const client = new FetchQL({ + url: 'https://your-graphql-server.com/graphql', + omitEmptyVariables: true +}); +``` + +## Conclusion + +Migrating to FetchQL from other GraphQL clients is straightforward. Its lightweight nature and unique features like built-in interceptors and enum type caching make it a powerful choice for many applications. By following this guide, you should be able to quickly adapt your existing GraphQL code to work with FetchQL. \ No newline at end of file