{"id":49859030,"url":"https://github.com/emirhangumus/zlient","last_synced_at":"2026-05-14T21:03:45.018Z","repository":{"id":320244612,"uuid":"1080815980","full_name":"emirhangumus/zlient","owner":"emirhangumus","description":"Build robust, type-safe API clients with runtime validation, retry logic, and zero boilerplate. Use any Standard Schema library — Zod, Valibot, ArkType, and more.","archived":false,"fork":false,"pushed_at":"2026-03-26T11:18:32.000Z","size":675,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-26T18:58:06.528Z","etag":null,"topics":["api-client","http","http-client","zod"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/zlient","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/emirhangumus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","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,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-21T23:00:18.000Z","updated_at":"2026-03-26T11:18:35.000Z","dependencies_parsed_at":"2025-10-22T19:30:08.904Z","dependency_job_id":null,"html_url":"https://github.com/emirhangumus/zlient","commit_stats":null,"previous_names":["emirhangumus/zlient"],"tags_count":31,"template":false,"template_full_name":null,"purl":"pkg:github/emirhangumus/zlient","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emirhangumus%2Fzlient","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emirhangumus%2Fzlient/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emirhangumus%2Fzlient/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emirhangumus%2Fzlient/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/emirhangumus","download_url":"https://codeload.github.com/emirhangumus/zlient/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emirhangumus%2Fzlient/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33043249,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"online","status_checked_at":"2026-05-14T02:00:06.663Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["api-client","http","http-client","zod"],"created_at":"2026-05-14T21:03:43.420Z","updated_at":"2026-05-14T21:03:45.009Z","avatar_url":"https://github.com/emirhangumus.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# zlient\n\n**The Type-Safe HTTP Client for Perfectionists.**\n\n![NPM Version](https://img.shields.io/npm/v/zlient?style=flat-square)\n![License](https://img.shields.io/npm/l/zlient?style=flat-square)\n![Downloads](https://img.shields.io/npm/dm/zlient?style=flat-square)\n\nBuild robust, type-safe API clients with runtime validation, retry logic, and zero boilerplate. Use **any** [Standard Schema](https://standardschema.dev) library — Zod, Valibot, ArkType, and more.\n\n## Features\n\n- **Standard Schema**: Use Zod, Valibot, ArkType, or any compatible validator. No lock-in.\n- **Functional API**: Define endpoints with pure functions and automatic type inference.\n- **Type-Safe**: Full TypeScript support. Arguments and responses are strictly typed.\n- **Runtime Validation**: Validate requests, responses, query params, and path params.\n- **Resilience**: Built-in exponential backoff retries and timeouts.\n- **Auth**: Logic-safe authentication providers (Bearer, API Key, Custom).\n- **Real-Time**: Type-safe WebSockets and Server-Sent Events (SSE).\n- **Observability**: Hooks for structured logging and metrics.\n\n---\n\n## Installation\n\n```bash\nnpm install zlient\n# or\nbun add zlient\n```\n\nThen install your preferred validation library:\n\n```bash\n# Pick one (or more!)\nnpm install zod       # Zod\nnpm install valibot   # Valibot  \nnpm install arktype   # ArkType\n```\n\n---\n\n## Quick Start\n\n### 1. Initialize Client\n\n```typescript\nimport { HttpClient } from 'zlient';\n\nconst client = new HttpClient({\n  baseUrls: {\n    default: 'https://api.example.com',\n  },\n  retry: { maxAttempts: 3, baseDelayMs: 1000 },\n});\n```\n\n### 2. Define Endpoint\n\nUse `createEndpoint` with your favorite schema library:\n\n\u003c!-- tabs:start --\u003e\n#### **Zod**\n```typescript\nimport { z } from 'zod';\n\nconst getUser = client.createEndpoint({\n  method: 'GET',\n  path: (params) =\u003e `/users/${params.id}`,\n  pathParams: z.object({ id: z.string() }),\n  response: z.object({\n    id: z.string(),\n    name: z.string(),\n    email: z.string().email(),\n  }),\n});\n```\n\n#### **Valibot**\n```typescript\nimport * as v from 'valibot';\n\nconst getUser = client.createEndpoint({\n  method: 'GET',\n  path: (params) =\u003e `/users/${params.id}`,\n  pathParams: v.object({ id: v.string() }),\n  response: v.object({\n    id: v.string(),\n    name: v.string(),\n    email: v.pipe(v.string(), v.email()),\n  }),\n});\n```\n\n#### **ArkType**\n```typescript\nimport { type } from 'arktype';\n\nconst getUser = client.createEndpoint({\n  method: 'GET',\n  path: (params) =\u003e `/users/${params.id}`,\n  pathParams: type({ id: 'string' }),\n  response: type({\n    id: 'string',\n    name: 'string',\n    email: 'string.email',\n  }),\n});\n```\n\u003c!-- tabs:end --\u003e\n\n### 3. Call It\n\nTypeScript will enforce inputs and infer the response type automatically.\n\n```typescript\nconst user = await getUser({\n  pathParams: { id: '123' },\n});\n\n// `user` is typed as { id: string; name: string; email: string }\nconsole.log(user.name);\n```\n\n---\n\n## Advanced Usage\n\n### Retry Configuration\n\nZlient automatically retries failed requests with exponential backoff. Customize the retry behavior:\n\n```typescript\nconst client = new HttpClient({\n  baseUrls: { default: 'https://api.example.com' },\n  retry: {\n    maxAttempts: 3,           // Total attempts (including initial request)\n    baseDelayMs: 1000,        // Base delay for exponential backoff\n    retryMethods: ['GET', 'POST', 'PUT'],     // Methods to retry\n    retryStatusCodes: [500, 502, 503, 504],   // Status codes to retry\n    respectRetryAfter: true,  // Honor Retry-After header\n  },\n});\n```\n\n### Authentication\n\nZlient provides built-in auth providers that safely handle headers.\n\n```typescript\nimport { BearerTokenAuth, ApiKeyAuth } from 'zlient';\n\n// Bearer Token (Dynamic)\nclient.setAuth(new BearerTokenAuth(async () =\u003e {\n  return await getLatestToken(); // Auto-refresh logic supported\n}));\n\n// API Key (Header or Query)\nclient.setAuth(new ApiKeyAuth({ header: 'X-API-KEY', value: 'secret' }));\n```\n\n### Multiple Status Codes\n\nHandle different responses for different status codes.\n\n```typescript\nimport { z } from 'zod';\n\nconst createPost = client.createEndpoint({\n  method: 'POST',\n  path: '/posts',\n  request: z.object({ title: z.string() }),\n  response: {\n    201: z.object({ id: z.string(), status: z.literal('created') }),\n    400: z.object({ error: z.string(), code: z.literal('validation_error') }),\n  },\n});\n\nconst result = await createPost({ data: { title: 'Hello' } });\n// `result` type is the union of the 201 and 400 schemas\n```\n\n### Error Handling\n\nValidation errors are thrown as `ApiError` with detailed issues:\n\n```typescript\nimport { ApiError } from 'zlient';\n\ntry {\n  await getUser({ pathParams: { id: '123' } });\n} catch (error) {\n  if (error instanceof ApiError \u0026\u0026 error.validationIssues) {\n    // Handle validation error\n    console.log(error.validationIssues);\n    // [{ message: 'Expected string, got number', path: ['id'] }]\n  }\n}\n```\n\n### FormData Support\n\nUpload files and send multipart form data seamlessly.\n\n```typescript\nimport { z } from 'zod';\n\nconst uploadFile = client.createEndpoint({\n  method: 'POST',\n  path: '/upload',\n  response: z.object({ fileId: z.string(), url: z.string() }),\n  advanced: {\n    skipRequestValidation: true, // FormData can't be validated\n  },\n});\n\nconst formData = new FormData();\nformData.append('file', fileBlob, 'document.pdf');\n\nconst result = await uploadFile({ data: formData });\n```\n\n### Metrics \u0026 Logging\n\nIntegrate with any monitoring stack (Datadog, Prometheus, etc.).\n\n```typescript\nimport { InMemoryMetricsCollector, ConsoleLogger } from 'zlient';\n\nconst client = new HttpClient({\n  baseUrls: { default: '...' },\n  logger: new ConsoleLogger(),\n  metrics: new InMemoryMetricsCollector(),\n});\n```\n\n### Real-Time (WebSockets \u0026 SSE)\n\nZlient makes real-time communication as simple as HTTP requests.\n\n#### **WebSockets**\n```typescript\nconst chatWs = client.createWebSocket({\n  path: '/chat',\n  send: z.object({ text: z.string() }),\n  receive: z.object({ user: z.string(), text: z.string() }),\n});\n\nconst socket = chatWs();\nsocket.on('message', (data) =\u003e console.log(data.text));\nsocket.send({ text: 'Hello!' });\n```\n\n#### **SSE**\n\nZlient's SSE implementation supports custom HTTP methods, request bodies, and **automatic authentication**.\n\n```typescript\nconst stream = client.createSSE({\n  path: '/events',\n  response: {\n    message: z.object({ type: z.literal('connected') }),\n    time: z.string(),\n  },\n  advanced: {\n    method: 'POST', // Support GET (default), POST, etc.\n  }\n});\n\nconst sse = await stream({\n  data: { filter: 'active' }, // Support request body for POST/PUT\n  headers: { 'X-Custom-ID': '123' }, // Custom headers\n});\n\nsse.on('message', (data) =\u003e console.log(data.type)); // Typed as { type: 'connected' }\nsse.on('time', (data) =\u003e console.log(data)); // Typed as string\n```\n\n---\n\n## Migration from v2\n\nv3 introduces Standard Schema support. Key changes:\n\n```diff\n- import { z } from 'zod'; // Required peer dependency\n+ // Use any Standard Schema library (Zod, Valibot, ArkType)\n\n- catch (e) { if (e instanceof ZodError) { ... } }\n+ catch (e) { if (e instanceof ApiError \u0026\u0026 e.validationIssues) { ... } }\n```\n\n---\n\n## Documentation\n\n📖 [Full Documentation](https://emirhangumus.github.io/zlient/)\n\n---\n\n## License\n\nMIT © [Emirhan Gumus](https://github.com/emirhangumus)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femirhangumus%2Fzlient","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Femirhangumus%2Fzlient","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femirhangumus%2Fzlient/lists"}