import { getItems } from './faker-types' interface CreateApiResourceOption { count: number depth: number fields: { [code: string]: { type: string } } } interface CreateApiResourceOptions { [name: string]: CreateApiResourceOption } interface CreateApiOptions { sortFieldKey: string } interface Model { id: number children: Model[] [resourceFieldCode: string]: any } type ModelField = string | number | boolean | Model | Model[] interface RequestConfig { params?: { [code: string]: string | string[] } } interface ResponseConfig { data: any status: number statusText: string headers: { [code: string]: string } config: { [code: string]: string } } function createFakeItems(resource: CreateApiResourceOption, depth: number, startOffset: { offset: number } = { offset: 0 }) { if (depth === 0) return [] const items: Model[] = [] for (let i = 0; i < resource.count; i++) { const item: Model = { id: startOffset.offset, children: [] } startOffset.offset += 1 if (Math.random() > 0.5) item.children = createFakeItems(resource, depth - 1, startOffset) Object.entries(resource.fields).forEach(([fieldKey, field]) => { const dataFromFaker = getItems(field.type) if (dataFromFaker !== undefined) { item[fieldKey] = dataFromFaker return } throw new Error(`Неизвестный тип поля ${field.type}`) }) items.push(item) } return items } export default function createApi(resources: CreateApiResourceOptions, options: CreateApiOptions) { const repository: { [code: string]: Model[] } = {} Object.entries(resources).forEach(([nameKey, resource]) => { repository[nameKey] = createFakeItems(resource, resource.depth) }) const find = (items: Model[], params: RequestConfig['params']): Model[] => { if (items === undefined) return [] if (params?.parent_id === undefined) return items return items.reduce((acc, item) => { if (params?.parent_id !== undefined && item.id === Number(params?.parent_id)) { return [...acc, ...item.children] } return [...acc, ...find(item.children, params)] }, [] as Model[]) } const get = (path: string, params: NonNullable) => { const explodedPath = path.split('/') if (explodedPath[0] === '') { explodedPath.shift() } const resourceType: keyof CreateApiResourceOptions = explodedPath[0] if (!(resourceType in repository)) { throw new Error(`В репозитории нет объектов типа ${resourceType}`) } if (!explodedPath[1] || explodedPath[1] === '') { const items = find(repository[resourceType], params) return { count: items.length, results: items.map((item: any) => { const result = { ...item } result.isEmpty = result.children.length === 0 delete result.children return result }), } } throw new Error(`Неизвестный тип запроса ${path}`) } return { request(url: string, data: any, config?: RequestConfig): Promise { const params: RequestConfig['params'] = config?.params || {} return new Promise((resolve) => { const data = get(url, params) setTimeout(() => { resolve({ data, status: 200, statusText: 'OK', headers: {}, config: {}, }) }, Math.random() * 1000) }) }, get(url: string, config?: RequestConfig): Promise { return this.request(url, {}, config) }, post(url: string, data: any, config?: RequestConfig): Promise { return this.request(url, data, config) }, put(url: string, data: any, config?: RequestConfig): Promise { return this.request(url, data, config) }, patch(url: string, data: any, config?: RequestConfig): Promise { return this.request(url, data, config) }, delete(url: string, config?: RequestConfig): Promise { return this.request(url, {}, config) }, } }