main
All checks were successful
UI Deploy (Next-Auth Support) 🎨 / build-and-deploy (push) Successful in 3m27s
All checks were successful
UI Deploy (Next-Auth Support) 🎨 / build-and-deploy (push) Successful in 3m27s
This commit is contained in:
84
README.md
84
README.md
@@ -212,39 +212,79 @@ toaster.error({ title: "Error", description: "Something went wrong." });
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📡 API Integration
|
## 📡 API Integration (Standard Architecture)
|
||||||
|
|
||||||
### Creating API Clients
|
The project follows a strict **Service + Hook** pattern for API integration to ensure separation of concerns, type safety, and efficient caching.
|
||||||
|
|
||||||
```tsx
|
**🏆 Golden Standard Reference:** [`src/lib/api/example`](src/lib/api/example)
|
||||||
// src/lib/api/auth/login/queries.ts
|
|
||||||
import { createApiClient } from "../create-api-client";
|
|
||||||
|
|
||||||
const api = createApiClient("/api/backend/auth");
|
### 🏗️ Architecture Pattern
|
||||||
|
|
||||||
export const loginUser = async (data: LoginDto) => {
|
For every domain (e.g., `auth`, `users`), we strictly follow this 4-layer structure:
|
||||||
const response = await api.post("/login", data);
|
|
||||||
return response.data;
|
| Layer | File | Purpose |
|
||||||
|
|-------|------|---------|
|
||||||
|
| **1. Types** | `types.ts` | **Contract:** pure TypeScript interfaces/DTOs matching Backend. |
|
||||||
|
| **2. Service** | `service.ts` | **Logic:** Pure functions calling `apiRequest`. Independent of React. |
|
||||||
|
| **3. Hooks** | `use-hooks.ts` | **State:** React Query wrappers (`useQuery`, `useMutation`) for caching & state. |
|
||||||
|
| **4. Barrel** | `index.ts` | **Public API:** Central export point for the module. |
|
||||||
|
|
||||||
|
### 📝 Implementation Guide
|
||||||
|
|
||||||
|
#### 1. Define Service (`service.ts`)
|
||||||
|
Uses `apiRequest` wrapper which handles client selection (`auth`, `core`, etc.), base URLs, and error normalization.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// src/lib/api/example/auth/service.ts
|
||||||
|
import { apiRequest } from "@/lib/api/api-service";
|
||||||
|
import { LoginDto, AuthResponse } from "./types";
|
||||||
|
|
||||||
|
const login = (data: LoginDto) => {
|
||||||
|
return apiRequest<ApiResponse<AuthResponse>>({
|
||||||
|
url: "/auth/login",
|
||||||
|
client: "auth", // Selects the correct axios instance from clientMap
|
||||||
|
method: "post",
|
||||||
|
data,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const authService = { login };
|
||||||
```
|
```
|
||||||
|
|
||||||
### React Query Integration
|
#### 2. Create Hook (`use-hooks.ts`)
|
||||||
|
Wraps service in TanStack Query for loading states, caching, and invalidation.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// src/lib/api/example/auth/use-hooks.ts
|
||||||
|
import { useMutation } from "@tanstack/react-query";
|
||||||
|
import { authService } from "./service";
|
||||||
|
|
||||||
|
export const AuthQueryKeys = {
|
||||||
|
all: ["auth"] as const,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useLogin() {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (data: LoginDto) => authService.login(data),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. Use in Components
|
||||||
|
Components only interact with the Hooks, never the Service or Axios directly.
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import { useQuery, useMutation } from "@tanstack/react-query";
|
import { useLogin } from "@/lib/api/example"; // Import from barrel
|
||||||
|
|
||||||
// Query hook
|
export function LoginForm() {
|
||||||
export const useUsers = () =>
|
const { mutate, isPending } = useLogin();
|
||||||
useQuery({
|
|
||||||
queryKey: ["users"],
|
|
||||||
queryFn: () => apiClient.get("/users"),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Mutation hook
|
const handleSubmit = (data) => {
|
||||||
export const useCreateUser = () =>
|
mutate(data, {
|
||||||
useMutation({
|
onSuccess: () => console.log("Logged in!"),
|
||||||
mutationFn: (data: CreateUserDto) => apiClient.post("/users", data),
|
});
|
||||||
});
|
};
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --webpack --experimental-https -p 3001",
|
"dev": "next dev --webpack -p 3001",
|
||||||
"build": "next build --webpack",
|
"build": "next build --webpack",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "eslint"
|
"lint": "eslint"
|
||||||
@@ -41,4 +41,4 @@
|
|||||||
"typescript": "^5"
|
"typescript": "^5"
|
||||||
},
|
},
|
||||||
"description": "Generated by Frontend CLI"
|
"description": "Generated by Frontend CLI"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user