{"id":44259875,"url":"https://github.com/k3dom/hono-rpc-query","last_synced_at":"2026-05-16T11:03:56.444Z","repository":{"id":292178096,"uuid":"980093761","full_name":"k3dom/hono-rpc-query","owner":"k3dom","description":"Integration for Hono's RPC client with React Query","archived":false,"fork":false,"pushed_at":"2026-05-10T16:54:33.000Z","size":439,"stargazers_count":40,"open_issues_count":11,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-05-10T18:34:06.706Z","etag":null,"topics":["hono","react-query","rpc"],"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/k3dom.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-05-08T14:52:00.000Z","updated_at":"2026-04-23T03:45:07.000Z","dependencies_parsed_at":"2025-05-15T19:14:07.175Z","dependency_job_id":null,"html_url":"https://github.com/k3dom/hono-rpc-query","commit_stats":null,"previous_names":["kedom1337/hono-rpc-query","k3dom/hono-rpc-query"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/k3dom/hono-rpc-query","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k3dom%2Fhono-rpc-query","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k3dom%2Fhono-rpc-query/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k3dom%2Fhono-rpc-query/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k3dom%2Fhono-rpc-query/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/k3dom","download_url":"https://codeload.github.com/k3dom/hono-rpc-query/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k3dom%2Fhono-rpc-query/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33100319,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-16T04:41:52.686Z","status":"ssl_error","status_checked_at":"2026-05-16T04:41:52.009Z","response_time":115,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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":["hono","react-query","rpc"],"created_at":"2026-02-10T16:47:59.215Z","updated_at":"2026-05-16T11:03:56.436Z","avatar_url":"https://github.com/k3dom.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🔥 hono-rpc-query\n\nEliminates boilerplate when integrating Hono's RPC client with TanStack React Query by automatically generating type-safe `queryOptions` and `mutationOptions` for all your endpoints.\n\n## Installation\n\n```bash\npnpm add hono-rpc-query\n# or\nnpm install hono-rpc-query\n# or\nyarn add hono-rpc-query\n```\n\n## Quick Start\n\n### 1. Set up your Hono server\n\n```typescript\n// server/index.ts\nimport { Hono } from 'hono'\nimport { zValidator } from '@hono/zod-validator'\nimport { z } from 'zod'\n\nconst app = new Hono()\nconst routes = app\n  .get('/posts', (c) =\u003e {\n    return c.json([\n      { id: 1, title: 'Hello World' },\n      { id: 2, title: 'Learning Hono' },\n    ])\n  })\n  .get(\n    '/posts/:id',\n    zValidator('param', z.object({ id: z.coerce.number() })),\n    (c) =\u003e {\n      const { id } = c.req.valid('param')\n      // ... fetch post logic\n      return c.json({ id, title: 'Post title' })\n    }\n  )\n  .post(\n    '/posts',\n    zValidator('json', z.object({ title: z.string(), content: z.string() })),\n    (c) =\u003e {\n      const data = c.req.valid('json')\n      // ... create post logic\n      return c.json({ id: 3, ...data })\n    }\n  )\n\nexport type AppRoutes = typeof routes\n```\n\n### 2. Create the client wrapper\n\n```typescript\n// client/api.ts\nimport { hc } from 'hono/client'\nimport { hcQuery } from 'hono-rpc-query'\nimport type { AppRoutes } from '../server'\n\nconst client = hc\u003cAppRoutes\u003e('http://localhost:3001')\nexport const api = hcQuery(client)\n```\n\n### 3. Use in your React components\n\n```typescript\nimport { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\nimport { api } from './api'\n\nfunction App() {\n  const queryClient = useQueryClient()\n\n  // Fetch all posts - note the empty object {} is required even with no input\n  const postsQuery = useQuery(api.posts.$get.queryOptions({}))\n\n  // Create post mutation - pass options directly to mutationOptions()\n  const createPost = useMutation(\n    api.posts.$post.mutationOptions({\n      onSuccess: () =\u003e {\n        queryClient.invalidateQueries({\n          queryKey: api.posts.$get.queryOptions({}).queryKey,\n        })\n      },\n    })\n  )\n\n  const handleCreate = () =\u003e {\n    createPost.mutate({ json: { title: 'New Post', content: 'Content' } })\n  }\n\n  return \u003cdiv\u003e{/* ... */}\u003c/div\u003e\n}\n```\n\n## API Reference\n\n### `queryOptions(config)`\n\nGenerates TanStack Query options for GET requests. Returns an object with `queryKey` and `queryFn`.\n\n**Important:** You must always pass an object to `queryOptions()`, even when there are no input arguments. Pass an empty object `{}` if no input is needed.\n\n#### Usage with no input\n\n```typescript\n// Endpoint with no parameters\nconst options = api.posts.$get.queryOptions({})\n// Returns: { queryKey: [...], queryFn: ... }\n\nuseQuery(options)\n```\n\n#### Usage with input parameters\n\n```typescript\n// Endpoint with path parameters\nconst options = api.posts[':id'].$get.queryOptions({\n  input: {\n    param: { id: '1' },\n  },\n})\n\nuseQuery(options)\n```\n\n#### Usage with json parameters\n\n```typescript\n// Endpoint with query string\nconst options = api.posts.$get.queryOptions({\n  input: {\n    json: { page: 1, limit: 10 },\n  },\n})\n\nuseQuery(options)\n```\n\n#### Additional TanStack Query options\n\nYou can pass any TanStack Query options alongside the input:\n\n```typescript\nconst options = api.posts.$get.queryOptions({\n  input: { param: { id: 1 } },\n  enabled: true,\n  staleTime: 5000,\n  refetchOnWindowFocus: false,\n})\n\nuseQuery(options)\n```\n\n#### Query cancellation\n\nBy default, `queryOptions()` does not consume TanStack Query's `AbortSignal`, matching TanStack Query's default behavior. If you want requests to be aborted when TanStack Query cancels a query, opt in with `abortOnCancel`:\n\n```typescript\nconst options = api.posts.$get.queryOptions({\n  input: { param: { id: 1 } },\n  abortOnCancel: true,\n})\n```\n\n### `mutationOptions(config)`\n\nGenerates TanStack Query options for POST, PUT, DELETE requests. Returns an object with `mutationKey` and `mutationFn`.\n\n**Important:** You must always pass an object to `mutationOptions()`, even when configuring no additional options. Pass an empty object `{}` if no config is needed.\n\n#### Basic usage\n\n```typescript\n// Always pass an object, even if empty\nconst mutation = useMutation(api.posts.$post.mutationOptions({}))\n\n// Call the mutation with input\nmutation.mutate({ json: { title: 'New Post', content: 'Content' } })\n```\n\n#### Usage with callbacks\n\nPass additional mutation options directly to `mutationOptions()`:\n\n```typescript\nconst mutation = useMutation(\n  api.posts.$post.mutationOptions({\n    onSuccess: (data) =\u003e {\n      console.log('Created:', data)\n    },\n    onError: (error) =\u003e {\n      console.error('Failed:', error)\n    },\n  })\n)\n```\n\n#### DELETE request example\n\n```typescript\nconst deleteMutation = useMutation(\n  api.posts[':id'].$delete.mutationOptions({\n    onSuccess: () =\u003e {\n      // Invalidate queries after deletion\n      queryClient.invalidateQueries({\n        queryKey: api.posts.$get.queryOptions({}).queryKey,\n      })\n    },\n  })\n)\n\n// Call with parameters\ndeleteMutation.mutate({ param: { id: '1' } })\n```\n\n### Accessing Query Keys\n\nYou can access the generated query key for cache invalidation or other purposes:\n\n```typescript\n// Get the query key\nconst queryKey = api.posts.$get.queryOptions({}).queryKey\n\n// Use it for invalidation\nqueryClient.invalidateQueries({ queryKey })\n\n// Use it for setting query data\nqueryClient.setQueryData(queryKey, newData)\n\n// Use it for getting cached data\nconst cachedData = queryClient.getQueryData(queryKey)\n```\n\n#### Query keys with parameters\n\n```typescript\n// Query key includes the input parameters\nconst queryKey = api.posts[':id'].$get.queryOptions({\n  input: { param: { id: 1 } },\n}).queryKey\n\n// Invalidate a specific post\nqueryClient.invalidateQueries({ queryKey })\n\n// Invalidate all posts (partial matching)\nqueryClient.invalidateQueries({\n  queryKey: ['posts'], // Matches all posts-related queries\n})\n```\n\n## Complete Example\n\nCheck out the [example](./example) directory for a full working implementation\n\n## Known Limitations\n\n- No support for `infiniteQueryOptions` (yet)\n\n## Contributing\n\nPull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.\n\nPlease make sure to update tests as appropriate.\n\n## License\n\n[MIT](https://choosealicense.com/licenses/mit/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fk3dom%2Fhono-rpc-query","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fk3dom%2Fhono-rpc-query","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fk3dom%2Fhono-rpc-query/lists"}