A CLI tool that generates a complete API structure with React Query (TanStack Query), Axios interceptors, and full TypeScript support. Zero configuration, maximum type safety.
npm install query-routingquery-routing scaffolds a complete architectural foundation for your API calls, combining Axios, TanStack Query (React Query), and TypeScript into a scalable, modular structure.
api/ directory structure in seconds.
openapi.yaml, openapi.yml, or openapi.json) to auto-generate routes and types.
src/ folder and places files accordingly.
axios, @tanstack/react-query) and installs them if missing.
req), Responses (res), and Routes.
useQuery and useMutation wrappers for consistent data fetching.
bash
npx query-routing
`
$3
To enable the automatic generation of types and routes from your backend:
1. Ensure your OpenAPI spec file is named exactly one of the following:
- openapi.yaml
- openapi.yml
- openapi.json
2. Place it in the root of your project.
3. Run the command!
$3
1. The CLI checks your package.json for dependencies.
2. It asks to install missing packages (Axios, TanStack Query) if needed.
3. It detects your openapi file and parses your endpoints.
4. It generates a structured api folder in your project root or src/api (if src exists).
---
š The Generated Structure
After running the command, your project will possess this modular architecture:
`text
src/api/
āāā š axios-config/
ā āāā interceptor.ts # Centralized Axios instance & error handling
āāā š enum/
ā āāā api-path.ts # String constants for API endpoints
āāā š hook/
ā āāā hook.ts # Generic useQueryWithAxios & useMutationWithAxios
āāā š req/
ā āāā req.types.ts # Request payload interfaces
āāā š res/
ā āāā res.types.ts # Response payload interfaces
āāā š types/
ā āāā api.types.ts # Generic Response Wrappers (IAxiosData)
ā āāā route.type.ts # The contract definitions for your routes
āāā api-route.ts # The runtime implementation of the routes
`
---
š Usage Guide
Once the files are generated, here is how you use the system in your day-to-day development.
$3
We provide a typed wrapper around React Query. You don't need to write fetch functions manually in your components.
`tsx
import React from "react";
import { useQueryWithAxios } from "./src/api/hook/hook";
export function UserList() {
// "auth" is the route group, "getUserInfo" is the method
const { data, isLoading, error } = useQueryWithAxios("auth", "getUserInfo");
if (isLoading) return Loading...;
if (error) return Error: {error.message};
return (
{/ data.data contains your actual payload /}
{data?.data.map((user) => (
- {user.name}
))}
);
}
`
$3
For POST, PUT, or DELETE requests:
`tsx
import { useMutationWithAxios } from "./src/api/hook/hook";
function CreateUserButton() {
const { mutate, isPending } = useMutationWithAxios("auth", "createUser");
const handleClick = () => {
mutate(
{ name: "John Doe", email: "john@example.com" }, // Strictly typed payload
{
onSuccess: (response) => {
console.log("User created:", response.data);
},
}
);
};
return (
);
}
`
---
š§© Workflow: Adding a New Route
To add a new API endpoint, follow this strict (but rewarding) cycle:
1. Define Types:
- Add request params to req/req.types.ts
- Add response shape to res/res.types.ts
2. Define Contract:
- Update types/route.type.ts to map the method name to the types.
3. Implement:
- Add the Axios call in api-route.ts using ApiPath constants.
Example:
`ts
// 1. types/route.type.ts
export interface IPostRoute {
getPosts: () => IResponse; // Define the signature
}
// 2. api-route.ts
export const ApiRoute: IAxiosRoute = {
posts: {
getPosts: () => api.get(ApiPath.POSTS), // Implement it
},
// ...
};
`
---
āļø Configuration
$3
Go to src/api/axios-config/interceptor.ts. This is where you inject tokens:
`ts
api.interceptors.request.use((config) => {
const token = localStorage.getItem("token");
if (token) {
config.headers.Authorization = Bearer ${token};
}
return config;
});
`
$3
Ensure your environment variables are set. The default configuration looks for:
`ts
const BASE_URL = import.meta.env.VITE_API_URL || process.env.REACT_APP_API_URL;
`
---
āļø License
MIT License
Copyright (c) 2025 Abdelhadi Alkayal
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
`
``