{"id":19936957,"url":"https://github.com/oliver-oloughlin/zod_api","last_synced_at":"2026-02-03T07:30:52.900Z","repository":{"id":187886238,"uuid":"677709086","full_name":"oliver-oloughlin/zod_api","owner":"oliver-oloughlin","description":"Configure API clients and endpoints using Zod","archived":false,"fork":false,"pushed_at":"2024-10-01T17:35:46.000Z","size":631,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-28T09:30:16.971Z","etag":null,"topics":["api","api-client","deno","typescript","zod"],"latest_commit_sha":null,"homepage":"","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/oliver-oloughlin.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,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-08-12T11:23:39.000Z","updated_at":"2024-10-01T17:34:47.000Z","dependencies_parsed_at":null,"dependency_job_id":"f1faa87c-1eec-4089-a506-a67cf2d02863","html_url":"https://github.com/oliver-oloughlin/zod_api","commit_stats":null,"previous_names":["oliver-oloughlin/zod_api"],"tags_count":37,"template":false,"template_full_name":null,"purl":"pkg:github/oliver-oloughlin/zod_api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oliver-oloughlin%2Fzod_api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oliver-oloughlin%2Fzod_api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oliver-oloughlin%2Fzod_api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oliver-oloughlin%2Fzod_api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oliver-oloughlin","download_url":"https://codeload.github.com/oliver-oloughlin/zod_api/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oliver-oloughlin%2Fzod_api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29037443,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-03T06:39:36.383Z","status":"ssl_error","status_checked_at":"2026-02-03T06:39:32.787Z","response_time":96,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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","api-client","deno","typescript","zod"],"created_at":"2024-11-12T23:29:56.525Z","updated_at":"2026-02-03T07:30:52.886Z","avatar_url":"https://github.com/oliver-oloughlin.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# zod_api\n\n_⚠️ This project is superseded by\n[jex](https://github.com/oliver-oloughlin/jex)_\n\nConfigure strongly typed API clients and endpoints using Zod schemas.\n\n## Client\n\n```ts\nimport { client, resource } from \"@olli/zod-api\"\n\nconst apiClient = client({\n  baseUrl: \"https://someapi.com/v1\",\n  resources: {\n    foo: resource(\"/foo\", {\n      actions: {\n        get: {\n          dataSchema: z.object({\n            bar: z.string(),\n            baz: z.number(),\n          }),\n        },\n      },\n    }),\n    bar: resource(\"/bar/:id\", {\n      // URL parameters schema is enforced by the given path, /baz/[id] pattern is also supported\n      urlParamsSchema: z.object({\n        id: z.number(),\n      }),\n      actions: {\n        post: {\n          searchParamsSchema: z.object({\n            q: z.string().optional(),\n          }),\n          bodySchema: z.object({\n            field1: z.string(),\n            field2: z.number(),\n          }),\n          headersSchema: z.object({\n            \"x-key\": z.string(),\n            \"x-secret\": z.string(),\n          }),\n        },\n      },\n    }),\n  },\n})\n```\n\nAction methods are inferred and explorable through auto-complete:\n\n```ts\nconst response1 = await apiClient.foo.get()\n\nconst resposne2 = await apiClient.bar.post({\n  urlParams: {\n    id: 123,\n  },\n  searchParams: {\n    q: \"query\",\n  },\n  body: {\n    field1: \"some string\",\n    field2: 42,\n  },\n  headers: {\n    \"x-key\": \"key\",\n    \"x-secret\": \"secret\",\n  },\n})\n```\n\nSetup authentication:\n\n```ts\nimport { z } from \"zod\"\nimport {\n  ApiKeyAuth,\n  BasicAuth,\n  BearerTokenAuth,\n  client,\n  resource,\n} from \"@olli/zod-api\"\n\n// Schemas\nconst ArtistSchema = z.object({\n  genres: z.array(z.string()),\n  href: z.string(),\n  id: z.string(),\n  name: z.string(),\n  popularity: z.number(),\n  type: z.enum([\"artist\"]),\n  uri: z.string(),\n})\n\nconst AccessTokenSchema = z.object({\n  access_token: z.string(),\n  token_type: z.enum([\"Bearer\"]),\n  expires_in: z.number(),\n})\n\n// Spotify API Client\nconst spotifyApiClient = client({\n  baseUrl: \"https://api.spotify.com/v1\",\n  logger: console,\n  fetcher: fetch,\n\n  // Setup authentication headers directly\n  requestParams: {\n    headers: {\n      \"x-api-key\": \"{api_key}\",\n    },\n  },\n\n  // API key authentication\n  auth: new ApiKeyAuth({ key: \"{api_key}\" }),\n\n  // Basic authentication\n  auth: new BasicAuth({\n    id: \"{api_id}\",\n    secret: \"{api_secret}\",\n  }),\n\n  // Bearer token authentication\n  auth: new BearerTokenAuth(AccessTokenSchema, {\n    tokenUrl: \"https://accounts.spotify.com/api/token\",\n    clientId: \"{client_id}\",\n    clientSecret: \"{client_secret}\",\n    mapper: (token) =\u003e token.access_token,\n    requestParams: {\n      body: new URLSearchParams({\n        grant_type: \"client_credentials\",\n      }),\n    },\n  }),\n\n  // Define resources\n  resources: {\n    artists: resource(\"/artists/:id\", {\n      urlParamsSchema: z.object({\n        id: z.string(),\n      }),\n      actions: {\n        get: {\n          dataSchema: ArtistSchema,\n        },\n      },\n    }),\n  },\n})\n```\n\n## Server (Deno)\n\nCreate a server with strongly typed endpoints:\n\n```ts\nimport { resource } from \"@olli/zod-api\"\nimport { serve } from \"@olli/zod-api/server/deno\"\n\nserve({\n  // Set options (optional)\n  options: {\n    hostname: \"localhost\",\n    port: 3000\n  },\n\n  // Create middleware (optional)\n  middleware: (req) =\u003e console.log(req.url)\n\n  // Define resources\n  resources: {\n    foo: resource(\"/foo/:id\", {\n      urlParamsSchema: z.object({\n        id: z.string(),\n      }),\n      actions: {\n        get: {\n          searchParams: z.object({\n            q: z.number(),\n          }),\n          dataSchema: z.object({\n            bar: z.string(),\n            baz: z.number(),\n          })\n        }\n      }\n    })\n  }\n}, {\n  foo: {\n    // ctx contains parsed body, headers, url and search parameters.\n    get: (req, ctx) =\u003e {\n      // Return successful response\n      return {\n        ok: true,\n        data: {\n          bar: ctx.urlParams.id,\n          baz: ctx.searchParams.q,\n        }\n      }\n\n      // or return error\n      return {\n        ok: false,\n        status: 401,\n        message: \"Unauthorized\"\n      }\n    }\n  }\n})\n```\n\n## Client \u0026 Server (Deno)\n\nWhen you want to configure both the client and the server for maximum\nsynchronization, you can do it the following way:\n\n```ts\nimport { client, config, resource } from \"@olli/zod-api\"\nimport { serve } from \"@olli/zod-api/server/deno\"\n\n// in config.ts\nconst apiConfig = config({\n  resources: {\n    foo: resource(\"/foo\", {\n      // ...\n    }),\n  },\n})\n\n// in client.ts\nconst apiClient = client({\n  ...apiConfig,\n  baseUrl: \"https://apihost.com\",\n})\n\n// in server.ts\nserve({\n  ...apiConfig,\n}, {\n  foo: {\n    // ...\n  },\n})\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foliver-oloughlin%2Fzod_api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foliver-oloughlin%2Fzod_api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foliver-oloughlin%2Fzod_api/lists"}