Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

MetaEngine GraphQL Fetch

npm version npm downloads License: MIT

Generate framework-agnostic TypeScript services and models from GraphQL schemas using the native Fetch API.

Typed queries, mutations & subscriptions, generated straight from your schema (SDL). Runs on Node, browsers, Vite, SvelteKit, Next.js, Bun, Deno, and any TS runtime that ships fetch. No runtime dependencies in the generated code.


Quick Links


Features

  • Framework-agnostic — works in any TS runtime with fetch
  • Native Fetch API — zero runtime dependencies in generated code
  • Queries, mutations & subscriptions — typed operations generated straight from SDL, with a shared executeGraphQL<T> helper
  • Reusable fragments — opt into named fragment spreads with --fragments
  • @oneOf inputs — idiomatic tagged-union input types with --one-of-inputs
  • Custom scalar mapping — well-known scalars resolve to idiomatic TS types; override any scalar with --custom-scalar
  • Production-ready — Bearer auth, timeouts, custom headers, retries, middleware, all via CLI flags
  • Smart error handling — opt into HTTP-status-based routing (--error-handling)
  • Result pattern — opt into ApiResult<T> for structured error handling without exceptions
  • Vite + SvelteKit--import-meta-env for import.meta.env access
  • Tree-shakeable — separate file per model and per operation type

Installation

npm install --save-dev @metaengine/graphql-fetch

Or use directly with npx:

npx @metaengine/graphql-fetch <input> <output>

Requirements

  • Node.js 18.0 or later
  • .NET 8.0 or later runtime (Download)
  • A TS runtime that supports fetch (Node 18+, all modern browsers, Bun, Deno)

Quick Start

Basic

npx @metaengine/graphql-fetch schema.graphql ./src/api \
  --documentation \
  --fragments

Production setup

npx @metaengine/graphql-fetch schema.graphql ./src/api \
  --bearer-auth API_TOKEN \
  --timeout 30 \
  --retries 3 \
  --custom-header X-Tenant-ID=TENANT_ID \
  --error-handling

With npm scripts

Add to your package.json:

{
  "scripts": {
    "generate:api": "metaengine-graphql-fetch schema.graphql ./src/api --fragments --error-handling"
  }
}

Then run:

npm run generate:api

Runtime-specific examples

Vite / SvelteKit (uses import.meta.env):

npx @metaengine/graphql-fetch schema.graphql ./src/api \
  --import-meta-env \
  --base-url-env VITE_API_URL

Next.js:

npx @metaengine/graphql-fetch schema.graphql ./src/api \
  --base-url-env NEXT_PUBLIC_API_URL

Plain Node / Bun / Deno:

npx @metaengine/graphql-fetch schema.graphql ./src/api \
  --base-url-env API_BASE_URL

More examples

# Reusable fragments + tagged-union @oneOf inputs
npx @metaengine/graphql-fetch schema.graphql ./src/api \
  --fragments \
  --one-of-inputs

# Map custom scalars to idiomatic TS types
npx @metaengine/graphql-fetch schema.graphql ./src/api \
  --custom-scalar DateTime=string \
  --custom-scalar UUID=string

CLI Options

Option Description Default
--fragments Emit reusable named fragments for object-type selections false
--one-of-inputs Generate idiomatic @oneOf input types (tagged-union inputs) false
--custom-scalar <Scalar=target> Map a GraphQL custom scalar to a TS type. Repeatable. See Custom scalar mappings -
--base-url-env <name> Environment variable name for base URL API_BASE_URL
--import-meta-env Use import.meta.env for env access (Vite, SvelteKit) false
--result-pattern Return ApiResult<T> instead of T for structured error handling false
--middleware Emit middleware hooks (onRequest, onResponse, onError) in client false
--error-handling Smart error handling based on HTTP status semantics false
--retries <max-attempts> Enable retries with exponential backoff (status codes 429, 503) -
--bearer-auth <env-var-name> Bearer token from env var (adds Authorization: Bearer <token>) -
--timeout <seconds> Request timeout in seconds for all operations -
--custom-header <header=envVarName> Static header from env var. Repeatable. -
--documentation Generate JSDoc comments from SDL descriptions false
--date-transformation Convert Date-typed scalar fields (e.g. DateTime) in responses to Date objects false
--options-threshold <n> Parameter count for options object 4
--service-suffix <suffix> Service naming suffix Service
--types-barrel Emit an index.ts barrel per folder plus a root index.ts re-exporting everything false
--clean Clean output directory (remove files not in generation) false
--verbose Enable verbose logging false
--help, -h Show help message -

Generated Code Structure

output/
  ├── models/                       # One file per type (object, input, enum, union)
  │   ├── user.ts                   # export interface User { ... }
  │   ├── role.ts                   # export type Role = 'ADMIN' | 'MEMBER' | ...
  │   ├── feed-item.ts              # union type alias
  │   ├── create-post-input.ts      # input object
  │   ├── scalars.ts                # custom scalar type aliases
  │   └── ...
  ├── services/                     # One file per root operation type
  │   ├── query.service.ts          # query operations
  │   ├── mutation.service.ts       # mutation operations
  │   ├── subscription.service.ts   # subscription operations
  │   └── fragments.ts              # (with --fragments) reusable named fragments
  ├── client.ts                     # ApiClient, createClient, getDefaultClient, executeGraphQL<T>
  └── errors.ts                     # GraphQLError / HttpError helpers

Each operation collapses to a one-line call to the shared executeGraphQL<T> helper in client.ts, which owns the POST /graphql request and the data/errors envelope handling. Query strings are hoisted to module-scope constants.


GraphQL features

Reusable fragments

npx @metaengine/graphql-fetch schema.graphql ./src/api --fragments

Emits services/fragments.ts with one named fragment per object type. Operation selections reference fragment spreads (...UserFields) instead of repeating field sets, keeping generated query strings DRY.

@oneOf inputs

npx @metaengine/graphql-fetch schema.graphql ./src/api --one-of-inputs

Renders @oneOf input types (October-2021 GraphQL spec) as idiomatic TypeScript discriminated unions where exactly one member may be set:

export type PostFilter =
  | { byAuthor: string; byTag?: never; byTitle?: never }
  | { byTag: string; byAuthor?: never; byTitle?: never }
  | { byTitle: string; byAuthor?: never; byTag?: never };

Without the flag, the input renders as a plain interface with all-optional fields.

Subscriptions

Subscription operations are generated into services/subscription.service.ts. The generated client accepts the WebSocket endpoint at runtime via ClientConfig.graphqlWsUrl (the framework performs the http→ws / https→wss upgrade on the base URL).


Production-ready features

Bearer authentication

npx @metaengine/graphql-fetch schema.graphql ./src/api --bearer-auth API_TOKEN

The generated client.ts exposes an auth config field accepting a token string or an async token provider (() => string | Promise<string>), and adds Authorization: Bearer <token> to every request.

Timeout

npx @metaengine/graphql-fetch schema.graphql ./src/api --timeout 30

Uses AbortSignal.timeout(seconds * 1000) and composes correctly with consumer-supplied AbortSignal.

Retries

npx @metaengine/graphql-fetch schema.graphql ./src/api --retries 3

Retries retryable responses (429, 503) up to the given number of attempts with exponential backoff.

Custom headers from env vars

npx @metaengine/graphql-fetch schema.graphql ./src/api \
  --custom-header X-Tenant-ID=TENANT_ID \
  --custom-header X-App-Id=APP_ID

Repeatable. Each header value comes from a separate env var (baked into the default client).

Smart error handling

npx @metaengine/graphql-fetch schema.graphql ./src/api --error-handling

Routes by HTTP status semantics: 403 / 404 return null; 400 / 409 / 422 return the error body; 401 / 500 / 502 / 503 throw.

Result pattern

npx @metaengine/graphql-fetch schema.graphql ./src/api --result-pattern

Operations return ApiResult<T> instead of throwing — handle errors as values rather than exceptions:

const result = await user(client, '123');
if (result.ok) {
  console.log(result.data?.displayName);
} else {
  console.error(result.error.message);
}

Middleware

npx @metaengine/graphql-fetch schema.graphql ./src/api --middleware

Generated client emits a Middleware interface (onRequest / onResponse / onError) and accepts a middleware array on ClientConfig. Composes with --bearer-auth, --timeout, --retries, and --error-handling.


Custom scalar mappings

GraphQL custom scalars resolve to idiomatic TypeScript types. Well-known scalars are mapped out of the box; any other custom scalar defaults to string.

GraphQL scalar TypeScript type
DateTime, Date, Time, DateTimeOffset Date
Decimal, Long, BigInt, ULong, UInt, Short, Byte number
UUID, Guid, Email, URL, URI string

Use --custom-scalar to override the TS type emitted for a scalar. Repeatable. Unsupported targets are hard errors — no silent fallbacks.

Target Emitted TS type
string string
number number
boolean boolean
Date Date
npx @metaengine/graphql-fetch schema.graphql ./src/api \
  --custom-scalar DateTime=string \
  --custom-scalar UUID=string

Integer-like scalars (Long, BigInt, ULong) map to number by design so values carried in request variables survive JSON.stringify. A bigint target is therefore not offered.


See it live

Try the generator with your own schema at https://www.metaengine.eu/converters.


Programmatic Usage

The NuGet package allows programmatic use in .NET projects. See the website documentation for full C# API reference.


Support


License

MIT License - see LICENSE file for details.


About This Repository

This is the documentation and issue tracking repository for MetaEngine GraphQL Fetch. The compiled NPM package is available at @metaengine/graphql-fetch.

Source code is proprietary, but the package is free to use under MIT license.

About

Generate TypeScript services and models from GraphQL schemas using the native Fetch API — typed queries, mutations & subscriptions, framework-agnostic

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors