mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
- Remove nested git repository from bugulma/frontend/.git - Add all frontend files to main repository tracking - Convert from separate frontend/backend repos to unified monorepo - Preserve all frontend code and development history as tracked files - Eliminate nested repository complexity for simpler development workflow This creates a proper monorepo structure with frontend and backend coexisting in the same repository for easier development and deployment.
122 lines
3.9 KiB
TypeScript
122 lines
3.9 KiB
TypeScript
/**
|
|
* Generic API service factory
|
|
* Reduces duplication in service layer by providing common CRUD operations
|
|
*/
|
|
|
|
import { z } from 'zod';
|
|
import { apiGet, apiPost, apiDelete } from '@/lib/api-client';
|
|
|
|
/**
|
|
* Options for creating a CRUD API service
|
|
*/
|
|
export interface CreateCRUDServiceOptions<
|
|
TEntity,
|
|
TCreateRequest,
|
|
TUpdateRequest = TCreateRequest,
|
|
> {
|
|
basePath: string;
|
|
entitySchema: z.ZodSchema<TEntity>;
|
|
createRequestSchema?: z.ZodSchema<TCreateRequest>;
|
|
updateRequestSchema?: z.ZodSchema<TUpdateRequest>;
|
|
}
|
|
|
|
/**
|
|
* Result of creating a CRUD service
|
|
*/
|
|
export interface CRUDService<TEntity, TCreateRequest, TUpdateRequest = TCreateRequest> {
|
|
getById: (id: string) => Promise<TEntity>;
|
|
list: (filters?: Record<string, unknown>) => Promise<TEntity[]>;
|
|
create: (request: TCreateRequest) => Promise<TEntity>;
|
|
update: (id: string, request: TUpdateRequest) => Promise<TEntity>;
|
|
delete: (id: string) => Promise<void>;
|
|
}
|
|
|
|
/**
|
|
* Creates a standard CRUD API service with validation
|
|
* Handles common patterns: GET, POST, PUT, DELETE with Zod validation
|
|
*/
|
|
export function createCRUDService<TEntity, TCreateRequest, TUpdateRequest = TCreateRequest>(
|
|
options: CreateCRUDServiceOptions<TEntity, TCreateRequest, TUpdateRequest>
|
|
): CRUDService<TEntity, TCreateRequest, TUpdateRequest> {
|
|
const { basePath, entitySchema, createRequestSchema, updateRequestSchema } = options;
|
|
|
|
const getById = async (id: string): Promise<TEntity> => {
|
|
const data = await apiGet<TEntity>(`${basePath}/${id}`);
|
|
return entitySchema.parse(data);
|
|
};
|
|
|
|
const list = async (filters?: Record<string, unknown>): Promise<TEntity[]> => {
|
|
const queryParams = new URLSearchParams();
|
|
if (filters) {
|
|
Object.entries(filters).forEach(([key, value]) => {
|
|
if (value !== undefined && value !== null) {
|
|
if (Array.isArray(value)) {
|
|
value.forEach((v) => queryParams.append(key, String(v)));
|
|
} else {
|
|
queryParams.append(key, String(value));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
const endpoint = `${basePath}${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
|
|
const data = await apiGet<TEntity[]>(endpoint);
|
|
return z.array(entitySchema).parse(data);
|
|
};
|
|
|
|
const create = async (request: TCreateRequest): Promise<TEntity> => {
|
|
const validated = createRequestSchema ? createRequestSchema.parse(request) : request;
|
|
const data = await apiPost<TEntity>(basePath, validated);
|
|
return entitySchema.parse(data);
|
|
};
|
|
|
|
const update = async (id: string, request: TUpdateRequest): Promise<TEntity> => {
|
|
const validated = updateRequestSchema ? updateRequestSchema.parse(request) : request;
|
|
const data = await apiPost<TEntity>(`${basePath}/${id}`, validated);
|
|
return entitySchema.parse(data);
|
|
};
|
|
|
|
const deleteById = async (id: string): Promise<void> => {
|
|
await apiDelete<void>(`${basePath}/${id}`);
|
|
};
|
|
|
|
return {
|
|
getById,
|
|
list,
|
|
create,
|
|
update,
|
|
delete: deleteById,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Creates a service function with validation
|
|
* Useful for non-CRUD endpoints
|
|
*/
|
|
export function createValidatedService<TRequest, TResponse>(
|
|
endpoint: string,
|
|
requestSchema: z.ZodSchema<TRequest>,
|
|
responseSchema: z.ZodSchema<TResponse>,
|
|
method: 'GET' | 'POST' = 'POST'
|
|
) {
|
|
return async (request: TRequest): Promise<TResponse> => {
|
|
const validated = requestSchema.parse(request);
|
|
|
|
let data: TResponse;
|
|
if (method === 'GET') {
|
|
const queryParams = new URLSearchParams();
|
|
Object.entries(validated as Record<string, unknown>).forEach(([key, value]) => {
|
|
if (value !== undefined && value !== null) {
|
|
queryParams.append(key, String(value));
|
|
}
|
|
});
|
|
const url = `${endpoint}${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
|
|
data = await apiGet<TResponse>(url);
|
|
} else {
|
|
data = await apiPost<TResponse>(endpoint, validated);
|
|
}
|
|
|
|
return responseSchema.parse(data);
|
|
};
|
|
}
|