up
This commit is contained in:
105
src/api/apiService.ts
Normal file
105
src/api/apiService.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import { ArticleDataType } from "@/types/article";
|
||||
import { ProductDataType } from "@/types/products";
|
||||
|
||||
|
||||
const BASE_URL = process.env.NEXT_PUBLIC_API_BASE ?? "http://localhost:5000";
|
||||
type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
||||
type QueryValue = string | number | boolean | null | undefined;
|
||||
type QueryParams = Record<string, QueryValue | QueryValue[]>;
|
||||
|
||||
interface RequestOptions<TBody = unknown> {
|
||||
method?: HttpMethod;
|
||||
params?: QueryParams;
|
||||
body?: TBody;
|
||||
signal?: AbortSignal;
|
||||
cache?: RequestCache;
|
||||
next?: NextFetchRequestConfig;
|
||||
}
|
||||
|
||||
export interface ListParams extends QueryParams {
|
||||
limit?: number; // THÊM limit
|
||||
page?: number;
|
||||
offset?: number;
|
||||
q?: string; // tuỳ chọn (search)
|
||||
sort?: string;
|
||||
categoryId?: number | string;
|
||||
}
|
||||
|
||||
function buildURL(path: string, params?: QueryParams) {
|
||||
const url = new URL(path, BASE_URL);
|
||||
if (params) {
|
||||
for (const [k, v] of Object.entries(params)) {
|
||||
if (Array.isArray(v)) {
|
||||
v.forEach((vv) => {
|
||||
if (vv !== undefined && vv !== null) url.searchParams.append(k, String(vv));
|
||||
});
|
||||
} else if (v !== undefined && v !== null) {
|
||||
url.searchParams.set(k, String(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
async function apiRequest<TResp = unknown, TBody = unknown>(
|
||||
endpoint: string,
|
||||
options: RequestOptions<TBody> = {}
|
||||
): Promise<TResp> {
|
||||
const {
|
||||
method = "GET",
|
||||
params,
|
||||
body,
|
||||
signal,
|
||||
cache = "no-store",
|
||||
next,
|
||||
} = options;
|
||||
|
||||
const url = buildURL(endpoint, params);
|
||||
|
||||
const res = await fetch(url, {
|
||||
method,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: body && method !== "GET" ? JSON.stringify(body) : undefined,
|
||||
signal,
|
||||
cache,
|
||||
next,
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const msg = await res.text().catch(() => res.statusText);
|
||||
throw new Error(`API ${method} ${endpoint} failed: ${res.status} ${msg}`);
|
||||
}
|
||||
return res.json() as Promise<TResp>;
|
||||
}
|
||||
|
||||
// API cho bài viết
|
||||
export const fetchListArticles = (params?: ListParams) =>
|
||||
apiRequest<{ list: ArticleDataType[]; total?: number }>("/article", {
|
||||
params,
|
||||
});
|
||||
|
||||
// GET /articleDetails?path=:slug
|
||||
export const fetchArticleDetail = (slug: string) =>
|
||||
apiRequest<ArticleDataType>("/articleDetails", {
|
||||
params: { path: slug },
|
||||
});
|
||||
|
||||
// API cho công việc
|
||||
export const fetchListProduct = (params?: ListParams) =>
|
||||
apiRequest<{ list: ProductDataType[]; total?: number }>("/product", {
|
||||
params,
|
||||
});
|
||||
export const fetchProductDetail = (slug: string) =>
|
||||
apiRequest<ProductDataType>("/productDetails", {
|
||||
params: { path: slug },
|
||||
});
|
||||
|
||||
|
||||
export const fetchProductsByCategoryId = (
|
||||
categoryId: number | string,
|
||||
params?: Omit<ListParams, "categoryId">
|
||||
) =>
|
||||
fetchListProduct({
|
||||
...params,
|
||||
categoryId,
|
||||
});
|
||||
Reference in New Issue
Block a user