fuapi
v0.0.24
Published
Fusion API between back-end and front-end
Readme
⚡ fuapi - Type-Safe Full-Stack API Framework
fuapi is an API framework designed specifically for TypeScript full-stack development, providing end-to-end type safety
🎯 Core Concepts
- Unified API Definition - Define once, share between frontend and backend
- Type Safety - Runtime type validation based on Zod schemas
- Automatic Inference - Automatic type inference for both client and server, no manual typing needed
- Standardized Communication - Uses POST method consistently for all data transmission
📝 API Definition Patterns
1. Return-Only API (RetAPI)
export const getHealthApi = defineAPI({
path: '/health',
voSchema: z.object({
status: z.string(),
uptime: z.number(),
timestamp: z.string(),
}),
})2. Input-Only API (ArgAPI)
export const createUserApi = defineAPI({
path: '/user/create',
dtoSchema: z.object({
name: z.string(),
email: z.string(),
}),
})3. Full Interaction API (StdAPI)
export const getUserApi = defineAPI({
path: '/user/get',
dtoSchema: z.object({
id: z.string(),
}),
voSchema: z.object({
id: z.string(),
name: z.string(),
email: z.string(),
}),
})4. No Parameters API (PlainAPI)
export const healthCheckApi = defineAPI({
path: '/health',
})🖥️ Backend Implementation (implApi)
// packages/server/src/api/user.ts
import {
getUserApi,
createUserApi,
getHealthApi,
} from '@quickest/apis'
import { implApi } from 'fuapi'
export function setupUserApis(app: Express) {
// Get user information
implApi({
express: app,
api: getUserApi,
handler: async ({ dto }) => {
const { id } = dto // All parameters passed through dto
// Return type automatically inferred as z.output<getUserApi.voSchema>
return {
id,
name: 'John Doe',
email: '[email protected]',
}
},
onError: (err) => {
console.error('API Error:', err)
},
})
// Create user
implApi({
express: app,
api: createUserApi,
handler: async ({ dto }) => {
// dto type automatically inferred as { name: string; email: string }
const user = await createUser(dto)
// No return value (void)
},
})
// Health check (no parameters)
implApi({
express: app,
api: getHealthApi,
handler: async ({ dto }) => {
// dto is void, no parameters
return {
status: 'OK',
uptime: process.uptime(),
timestamp: new Date().toISOString(),
}
},
})
}🎨 Frontend Usage (clientOfAPI)
// packages/web-app/src/apis/user.ts
import { getUserApi, createUserApi, getHealthApi } from '@quickest/apis'
import { clientOfAPI } from 'fuapi'
// Create clients
export const getUserClient = clientOfAPI({
api: getUserApi,
axios: axiosInstance,
onError: async (err) => {
console.error('Request failed:', err)
}
})
export const createUserClient = clientOfAPI({
api: createUserApi,
axios: axiosInstance
})
export const getHealthClient = clientOfAPI({
api: getHealthApi,
axios: axiosInstance
})
// Usage in React components
function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState(null)
const [health, setHealth] = useState(null)
useEffect(() => {
// All parameters passed through dto
getUserClient({ id: userId }).then(setUser)
// No parameter API call
getHealthClient().then(setHealth)
// Create user
createUserClient({
name: "Jane",
email: "[email protected]"
})
}, [userId])
return (
<div>
<div>User: {user?.name}</div>
<div>Service Status: {health?.status}</div>
</div>
)
}🔧 Advanced Usage
Parameter Passing
// fuapi doesn't support path parameters, all parameters must be passed through dto
export const getUserPostsApi = defineAPI({
path: '/user/posts', // Clean path
dtoSchema: z.object({
userId: z.string(),
postId: z.string().optional(),
limit: z.number().optional(),
}),
voSchema: z.object({
posts: z.array(
z.object({
id: z.string(),
title: z.string(),
})
),
}),
})Error Handling
// Backend unified error handling
implApi({
api: myApi,
handler: async ({ dto }) => {
throw new Error('Something went wrong') // Will be caught by onError
},
onError: (err) => {
logger.error(err)
// Can return custom error response
},
})
// Frontend error handling
const client = clientOfAPI({
api: myApi,
axios: axiosInstance,
onError: async (err) => {
// Handle network errors, validation errors, etc.
showNotification('Request failed')
},
})Request Configuration
const client = clientOfAPI({
api: myApi,
axios: axiosInstance,
requestConfig: {
timeout: 5000,
headers: { 'Custom-Header': 'value' },
},
})🎯 Type Safety Benefits
- Compile-time Checking - Frontend and backend errors synchronously when API interface changes
- Auto-completion - IDE provides complete parameter and return value suggestions
- Runtime Validation - Zod ensures data format correctness
- Refactoring Friendly - Frontend and backend update together when renaming fields
