hono-rq
v0.1.1
Published
React Query integration for Hono RPC client with zero overhead
Maintainers
Readme
hono-rq
A zero-overhead React Query integration for Hono RPC clients with full type safety.
Features
- 🔒 Full Type Safety - Preserves all Hono RPC types end-to-end
- 🚀 Zero Runtime Overhead - Minimal proxy-based implementation
- ⚡ React Query Integration - Generate
queryOptions,infiniteQueryOptions, andmutationOptions - 🎯 Smart Query Keys - Automatic, stable query key generation based on endpoint and parameters
- 🌟 Developer Experience - IntelliSense support with autocomplete for all endpoints
- 🧪 Well Tested - Comprehensive test coverage including browser and integration tests
- 📦 Tree Shakable - Only bundle what you use
Installation
npm install hono-rq @tanstack/react-query honopnpm add hono-rq @tanstack/react-query honoyarn add hono-rq @tanstack/react-query honobun add hono-rq @tanstack/react-query honoQuick Start
1. Extend your Hono client
import { extend } from 'hono-rq';
import { hc } from 'hono/client';
import type { AppType } from './server'; // Your Hono app type
const client = hc<AppType>('http://localhost:3000');
const extendedClient = extend(client);2. Use with React Query
import { useQuery, useMutation } from '@tanstack/react-query';
function UsersList() {
// Generate query options for GET requests
const queryOptions = extendedClient.users.$get.queryOptions();
const { data, isLoading, error } = useQuery(queryOptions);
// Generate mutation options for POST requests
const mutationOptions = extendedClient.users.$post.mutationOptions();
const createUser = useMutation(mutationOptions);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
{data?.users.map(user => (
<div key={user.id}>{user.name}</div>
))}
<button
onClick={() => createUser.mutate({
json: { name: 'New User', email: '[email protected]' }
})}
>
Add User
</button>
</div>
);
}API Reference
extend(client)
Extends a Hono RPC client with React Query integration methods.
import { extend } from 'hono-rq';
const extendedClient = extend(client);Parameters:
client- Any Hono RPC client created withhc<AppType>()
Returns:
- Extended client with React Query methods added to each endpoint
Query Options
Generate React Query options for GET endpoints:
// Basic usage
const queryOptions = extendedClient.users.$get.queryOptions();
// With parameters
const queryOptions = extendedClient.users[':id'].$get.queryOptions({
param: { id: '123' }
});
// With query parameters
const queryOptions = extendedClient.users.$get.queryOptions({
query: { limit: '10', offset: '0' }
});
// With React Query options
const queryOptions = extendedClient.users.$get.queryOptions(
{ query: { limit: '10' } },
{
enabled: true,
staleTime: 5000,
retry: 3
}
);Infinite Query Options
Generate options for paginated data with React Query's infinite queries:
const infiniteQueryOptions = extendedClient.posts.$get.infiniteQueryOptions(
(pageParam) => ({
query: {
page: pageParam?.toString() ?? '1',
limit: '10'
}
}),
{
initialPageParam: 1,
getNextPageParam: (lastPage, pages) =>
lastPage.hasMore ? pages.length + 1 : undefined,
}
);
const {
data,
fetchNextPage,
hasNextPage,
isLoading
} = useInfiniteQuery(infiniteQueryOptions);Mutation Options
Generate options for POST, PUT, PATCH, DELETE endpoints:
// Basic mutation
const mutationOptions = extendedClient.users.$post.mutationOptions();
// With React Query options
const mutationOptions = extendedClient.users[':id'].$patch.mutationOptions(
undefined,
{
onSuccess: (data) => {
console.log('User updated:', data);
},
onError: (error) => {
console.error('Update failed:', error);
}
}
);
const mutation = useMutation(mutationOptions);TypeScript
hono-rq is built with TypeScript and provides full type safety:
// All types are preserved from your Hono app
type UsersResponse = InferResponseType<typeof extendedClient.users.$get>;
type CreateUserRequest = InferRequestType<typeof extendedClient.users.$post>;
// Query options have correct types
const queryOptions = extendedClient.users.$get.queryOptions();
// queryOptions.queryFn return type matches your Hono endpoint
// Mutations are fully typed
const mutation = useMutation(
extendedClient.users.$post.mutationOptions()
);
// mutation.mutate() expects the correct request typeAdvanced Usage
Error Handling
const queryOptions = extendedClient.users.$get.queryOptions(undefined, {
retry: (failureCount, error) => {
// Custom retry logic
if (error.status === 404) return false;
return failureCount < 3;
},
onError: (error) => {
console.error('Query failed:', error);
}
});Examples
Complete CRUD Example
import { extend } from 'hono-rq';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
const extendedClient = extend(client);
function UserManager() {
const queryClient = useQueryClient();
// List users
const usersQuery = useQuery(
extendedClient.users.$get.queryOptions()
);
// Get single user
const userQuery = useQuery(
extendedClient.users[':id'].$get.queryOptions({
param: { id: selectedUserId }
}, {
enabled: !!selectedUserId
})
);
// Create user
const createUser = useMutation(
extendedClient.users.$post.mutationOptions(undefined, {
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: extendedClient.users.$get.queryOptions().queryKey
});
}
})
);
// Update user
const updateUser = useMutation(
extendedClient.users[':id'].$patch.mutationOptions(undefined, {
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['users'] });
}
})
);
// Delete user
const deleteUser = useMutation(
extendedClient.users[':id'].$delete.mutationOptions(undefined, {
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['users'] });
}
})
);
return (
<div>
{/* Your UI here */}
</div>
);
}Requirements
- Node.js: 18+
- React: 18+
- @tanstack/react-query: 5.0+
- hono: 4.0+
- TypeScript: 5.0+ (recommended)
Contributing
We welcome contributions! Please see our Contributing Guide for details.
License
MIT © Peter Ferguson
Related Projects
- Hono - Ultrafast web framework for the Edges
- TanStack Query - Powerful data synchronization for web applications
- tRPC - End-to-end typesafe APIs made easy
