JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 2
  • Score
    100M100P100Q78000F
  • License ISC

Generate a graphql client sdk for any graphql api

Package Exports

    This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (buro26-graphql-codegen-client) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

    Readme

    GraphQL Codegen Client

    Generate a secure, high-performance client SDK for your GraphQL API using GraphQL Codegen. Features include per-user caching, rate limiting, error handling, and middleware support.

    Getting started

    npm i --save-dev buro26-graphql-codegen-client buro26-graphql-codegen-zod @graphql-codegen/cli @graphql-codegen/schema-ast @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typed-document-node

    Usage

    Create a codegen.ts file in the root of your project with the following content:

    import type {CodegenConfig} from '@graphql-codegen/cli'
    
    const config: CodegenConfig = {
        schema: 'http://localhost:1337/graphql',
        documents: 'src/lib/strapi/queries/**/!(*.generated).{ts,tsx}',
        debug: true,
        overwrite: true,
        verbose: true,
        generates: {
            // optional: generate schema types
            './schema.graphql': {
                plugins: ['schema-ast']
            },
            'src/lib/my-api/generated/types.ts': {
                plugins: ['typescript', 'typescript-operations', 'typed-document-node'],
                config: {
                    withHooks: false,
                    maybeValue: 'T | null',
                    avoidOptionals: false
                }
            },
            'src/lib/my-api/generated/client-factory.ts': {
                plugins: ['buro26-graphql-codegen-client'],
                config: {
                    logger: true,
                    typesImportPath: '@/lib/strapi/generated/types',
                    schemaImportPath: '@/lib/strapi/generated/schema'
                }
            },
            'src/lib/my-api/generated/schema.ts': {
                plugins: ['buro26-graphql-codegen-zod'],
                config: {
                    onlyWithValidation: false,
                    lazy: true,
                    zodTypesMap: {
                        DateTime: 'string',
                        JSON: 'string',
                        ID: 'string',
                        Int: 'number',
                        Float: 'number',
                        Long: 'number',
                        String: 'string',
                        Boolean: 'boolean',
                        I18NLocaleCode: 'string'
                    },
                    zodSchemasMap: {
                        DateTime: 'z.string()',
                        JSON: 'z.any()',
                        Long: 'z.coerce.number()',
                        I18NLocaleCode: 'z.string()'
                    }
                }
            }
        }
    }
    export default config

    Add a script to your package.json to run the codegen:

    {
      "scripts": {
        "codegen": "graphql-codegen"
      }
    }

    Run the codegen script:

    npm run codegen

    Create a client from the generated code:

    import {createClient} from '@/lib/my-api/generated/client-factory'
    
    export const client = createClient({
        url: process.env.MY_API_URL!,
        logging: true,
        
        // Optional: Global error handling
        onError: (error, operation) => {
            console.error('GraphQL Error:', error.message)
            // Send to error tracking service (Sentry, etc.)
        },
        
        // Optional: Rate limit handling
        onRateLimitExceeded: (type, token) => {
            console.warn('Rate limit exceeded:', type)
            // Show user notification or implement backoff strategy
        }
    })

    Make a request

    Import the client and make a request:

    import {client} from '@/lib/my-api/client'
    
    const {data} = await client.query.adres.fetch({
        authToken: ctx.session?.accessToken,
        variables: {
            filters: {
                id: {
                    eq: id
                }
            }
        }
    })

    Per-operation error handling

    You can also handle errors for specific operations:

    const {data} = await client.query.adres.fetch({
        authToken: ctx.session?.accessToken,
        variables: { filters: { id: { eq: id } } },
        
        // Custom error handler for this specific operation
        onError: (error) => {
            console.log('Custom error handler:', error.message)
            // This will be called in addition to the global onError callback
        }
    })

    Use the schema

    Import the schema and use it to validate data. This is useful for example for form validation, or usage with tRPC.

    procedure
        .input(
            client.query.adres.schema()
        )
        .query(async ({input, ctx}) => {
            const {data} = await client.query.adres.fetch({
                authToken: ctx.session?.accessToken,
                variables: input
            })
    
            return data?.adressen?.data[0] ?? null
        })

    Features

    🔒 Security Features

    • Per-user cache isolation: Each user's data is cached separately to prevent cross-user data leakage
    • Rate limiting: Built-in rate limiting with configurable limits (100 requests/minute per user, 10k global)
    • Token-based authentication: Secure token handling with proper isolation
    • Request deduplication: Prevents duplicate requests while maintaining security

    ⚡ Performance Features

    • Intelligent caching: 500ms minimum cache duration with automatic cleanup
    • Request deduplication: Identical requests are deduplicated to reduce server load
    • Cached requests don't count against rate limits: Better user experience
    • Memory efficient: Per-user cache instances with automatic cleanup

    🛠️ Developer Experience

    • TypeScript support: Full type safety with generated types
    • Error handling: Global and per-operation error callbacks
    • Rate limit monitoring: Callbacks for rate limit events
    • Middleware support: Custom middleware for request/response processing
    • Logging: Built-in logging with configurable levels

    📊 Monitoring & Observability

    const client = createClient({
        url: process.env.API_URL!,
        logging: true,
        
        // Monitor errors
        onError: (error, operation) => {
            // Send to error tracking service
            analytics.track('graphql_error', {
                message: error.message,
                operation: operation.kind,
                operationName: operation.context.operationName
            })
        },
        
        // Monitor rate limits
        onRateLimitExceeded: (type, token) => {
            // Track rate limit events
            analytics.track('rate_limit_exceeded', {
                type,
                userId: extractUserIdFromToken(token)
            })
        }
    })

    Configuration Options

    Client Options

    interface ClientOptions {
        url: string                    // GraphQL endpoint URL
        logging?: boolean             // Enable/disable logging (default: false)
        middlewares?: Middleware[]    // Custom middleware functions
        onError?: ClientErrorCallback // Global error handler
        onRateLimitExceeded?: RateLimitExceededCallback // Rate limit handler
    }

    Rate Limiting Configuration

    The client includes built-in rate limiting with the following defaults:

    • Per-user limit: 100 requests per minute
    • Global limit: 10,000 requests per minute
    • Window: 60 seconds

    Rate limits apply to both queries and mutations, but cached requests don't count against limits.

    Cache Configuration

    • Cache duration: 500ms minimum
    • Per-user isolation: Each user has separate cache instances
    • Automatic cleanup: Expired entries are automatically removed
    • Memory efficient: Only caches requests with valid authentication tokens

    Test and Deploy

    Running tests

    To run tests, run the following command:

    bun test

    Contributing

    Wish to contribute to this project? Pull the project from the repository and create a merge request.

    Authors and acknowledgment

    Buro26 - https://buro26.digital
    Special thanks to all contributors and the open-source community for their support and contributions.

    License

    This project is licensed under the MIT License - see the LICENSE file for details.

    Project status

    The project is currently in active development. We are continuously working on adding new features and improving the existing ones. Check the issues section for the latest updates and planned features.

    Feel free to reach out if you have any questions or suggestions!