Добавление функции враппера для api объектов, доработка http объекта (#36)
This commit is contained in:
@ -55,6 +55,7 @@
|
|||||||
"class-methods-use-this": 0,
|
"class-methods-use-this": 0,
|
||||||
"react/prefer-stateless-function": 0,
|
"react/prefer-stateless-function": 0,
|
||||||
"react/jsx-fragments": 0,
|
"react/jsx-fragments": 0,
|
||||||
|
"react/jsx-key": "warn",
|
||||||
"react/no-array-index-key": 0,
|
"react/no-array-index-key": 0,
|
||||||
"react/destructuring-assignment": 0,
|
"react/destructuring-assignment": 0,
|
||||||
"no-console": [
|
"no-console": [
|
||||||
@ -95,6 +96,7 @@
|
|||||||
"@typescript-eslint/no-namespace": "off",
|
"@typescript-eslint/no-namespace": "off",
|
||||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||||
"@typescript-eslint/no-unused-vars": ["error"],
|
"@typescript-eslint/no-unused-vars": ["error"],
|
||||||
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
"array-bracket-spacing": ["warn", "never"],
|
"array-bracket-spacing": ["warn", "never"],
|
||||||
"block-spacing": ["warn", "never"],
|
"block-spacing": ["warn", "never"],
|
||||||
"brace-style": ["warn", "1tbs", {"allowSingleLine": true}],
|
"brace-style": ["warn", "1tbs", {"allowSingleLine": true}],
|
||||||
|
|||||||
@ -1,70 +0,0 @@
|
|||||||
import {makeStorageApi} from './StorageApi';
|
|
||||||
|
|
||||||
type Region = {
|
|
||||||
name: string;
|
|
||||||
subject_number: number;
|
|
||||||
gibdd_codes: Array<number>;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ResponseRegions = {
|
|
||||||
regions: Array<Region>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const api = makeStorageApi<ResponseRegions>({
|
|
||||||
key: 'russian_regions',
|
|
||||||
hook: '26502372-6bc4-4cdf-bbcc-41b3b71cb386',
|
|
||||||
description: 'Регионы России',
|
|
||||||
service_name: 'geo_services',
|
|
||||||
});
|
|
||||||
|
|
||||||
export const regionsApi = {
|
|
||||||
request: async (): Promise<Region[]> => {
|
|
||||||
const {value: {regions}} = await api.request();
|
|
||||||
return regions;
|
|
||||||
},
|
|
||||||
find: async (name: string): Promise<Undefinable<Region>> => {
|
|
||||||
const regions = await regionsApi.request();
|
|
||||||
return regions.find(region => region.name === name);
|
|
||||||
},
|
|
||||||
create: async (newRegion: Region): Promise<Region> => {
|
|
||||||
const regions = await regionsApi.request();
|
|
||||||
const findedRegion = regions.find(region => region.name === newRegion.name);
|
|
||||||
if (findedRegion) {
|
|
||||||
throw new Error(`Город с именем "${newRegion.name}" уже существует`);
|
|
||||||
}
|
|
||||||
await api.update({
|
|
||||||
regions: [
|
|
||||||
...regions,
|
|
||||||
newRegion,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
return newRegion;
|
|
||||||
},
|
|
||||||
update: async (updatedRegion: Region): Promise<Region> => {
|
|
||||||
const regions = await regionsApi.request();
|
|
||||||
const findedIndex = regions.findIndex(region => region.name === updatedRegion.name);
|
|
||||||
if (findedIndex === -1) {
|
|
||||||
throw new Error(`Город с именем "${updatedRegion.name}" не найден`);
|
|
||||||
}
|
|
||||||
await api.update({
|
|
||||||
regions: regions.map((region, index) => {
|
|
||||||
if (findedIndex === index) {
|
|
||||||
return updatedRegion;
|
|
||||||
}
|
|
||||||
return region;
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
return updatedRegion;
|
|
||||||
},
|
|
||||||
remove: async (name: string): Promise<string> => {
|
|
||||||
const regions = await regionsApi.request();
|
|
||||||
const findedIndex = regions.findIndex(region => region.name === name);
|
|
||||||
if (findedIndex === -1) {
|
|
||||||
throw new Error(`Город с именем "${name}" не найден`);
|
|
||||||
}
|
|
||||||
await api.update({
|
|
||||||
regions: regions.filter(region => region.name === name),
|
|
||||||
});
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
import {http} from '../infrastructure/Http';
|
|
||||||
|
|
||||||
type QueryRequest = {
|
|
||||||
hook: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResponseData<T> = {
|
|
||||||
key: string;
|
|
||||||
value: T;
|
|
||||||
description: string;
|
|
||||||
service_name: string;
|
|
||||||
author: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type RequestData<T> = Omit<ResponseData<T>, 'author'>;
|
|
||||||
|
|
||||||
type ApiConfig<T> = Omit<ResponseData<T>, 'value' | 'author'> & {
|
|
||||||
hook: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type Api<T> = {
|
|
||||||
request: () => Promise<ResponseData<T>>;
|
|
||||||
update: (updateValue: T) => Promise<ResponseData<T>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ROOT_URL = 'https://api.storage.vigdorov.ru/store';
|
|
||||||
|
|
||||||
export const makeStorageApi = <T>({key, hook, ...body}: ApiConfig<T>): Api<T> => {
|
|
||||||
const config = {params: {hook}};
|
|
||||||
return {
|
|
||||||
request: async (): Promise<ResponseData<T>> => {
|
|
||||||
const {data} = await http.get<QueryRequest, ResponseData<T>>(`${ROOT_URL}/${key}`, config);
|
|
||||||
return data;
|
|
||||||
},
|
|
||||||
update: async (updateValue: T): Promise<ResponseData<T>> => {
|
|
||||||
const {data} = await http.put<QueryRequest, RequestData<T>, ResponseData<T>>(ROOT_URL, {
|
|
||||||
...body,
|
|
||||||
key,
|
|
||||||
value: updateValue,
|
|
||||||
}, config);
|
|
||||||
return data;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
29
src/core/api/usersTestApi.ts
Normal file
29
src/core/api/usersTestApi.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import {http} from '../infrastructure/Http';
|
||||||
|
import {makeApi} from '../utils/makeApi';
|
||||||
|
|
||||||
|
type User = {
|
||||||
|
id: number;
|
||||||
|
avatar: string;
|
||||||
|
email: string;
|
||||||
|
first_name: string;
|
||||||
|
last_name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type UserReponse = {
|
||||||
|
data: Array<User>;
|
||||||
|
page: number;
|
||||||
|
per_page: number;
|
||||||
|
support: {
|
||||||
|
text: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
total: number;
|
||||||
|
total_pages: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usersApi = makeApi({
|
||||||
|
request: async () => {
|
||||||
|
const {data} = await http.get<void, UserReponse>('https://reqres.in/api/users');
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
});
|
||||||
@ -1,53 +1,51 @@
|
|||||||
import axios, {AxiosRequestConfig, AxiosResponse} from 'axios';
|
import axios, {AxiosRequestConfig} from 'axios';
|
||||||
|
|
||||||
type RequestConfig<Q> = Omit<AxiosRequestConfig, 'params'> & {
|
enum Method {
|
||||||
params: Q;
|
Get = 'get',
|
||||||
|
Delete = 'delete',
|
||||||
|
Head = 'head',
|
||||||
|
Options = 'options',
|
||||||
|
Post = 'post',
|
||||||
|
Put = 'put',
|
||||||
|
Patch = 'patch',
|
||||||
|
}
|
||||||
|
|
||||||
|
type RequestConfig<Q, B> = Omit<AxiosRequestConfig, 'params' | 'data'> & {
|
||||||
|
params?: Q;
|
||||||
|
data?: B;
|
||||||
|
};
|
||||||
|
|
||||||
|
const requestMiddleware = async <Q, B, R>(config: RequestConfig<Q, B>): Promise<R> => {
|
||||||
|
const axiosResponse = await axios.request<R>(config);
|
||||||
|
// Добавить обработку ошибок
|
||||||
|
return axiosResponse.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const request = <Q, B, R>(config: RequestConfig<Q, B>) => requestMiddleware<Q, B, R>(config);
|
||||||
|
|
||||||
|
const requestWithoutBody = (method: Method) => <Q, R>(url: string, query?: Q) => {
|
||||||
|
return request<Q, never, R>({
|
||||||
|
method,
|
||||||
|
url,
|
||||||
|
params: query,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const requestWithBody = (method: Method) => <Q, B, R>(url: string, query?: Q, body?: B) => {
|
||||||
|
return request<Q, B, R>({
|
||||||
|
method,
|
||||||
|
url,
|
||||||
|
params: query,
|
||||||
|
data: body,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const http = {
|
export const http = {
|
||||||
get: <Query, Response>(
|
get: requestWithoutBody(Method.Get),
|
||||||
url: string,
|
delete: requestWithoutBody(Method.Delete),
|
||||||
config: RequestConfig<Query>
|
head: requestWithoutBody(Method.Head),
|
||||||
): Promise<AxiosResponse<Response>> => {
|
options: requestWithoutBody(Method.Options),
|
||||||
return axios.get<Response>(url, config);
|
post: requestWithBody(Method.Post),
|
||||||
},
|
put: requestWithBody(Method.Put),
|
||||||
delete: <Query, Response>(
|
patch: requestWithBody(Method.Patch),
|
||||||
url: string,
|
|
||||||
config: RequestConfig<Query>
|
|
||||||
): Promise<AxiosResponse<Response>> => {
|
|
||||||
return axios.delete<Response>(url, config);
|
|
||||||
},
|
|
||||||
head: <Query, Response>(
|
|
||||||
url: string,
|
|
||||||
config: RequestConfig<Query>
|
|
||||||
): Promise<AxiosResponse<Response>> => {
|
|
||||||
return axios.head<Response>(url, config);
|
|
||||||
},
|
|
||||||
options: <Query, Response>(
|
|
||||||
url: string,
|
|
||||||
config: RequestConfig<Query>
|
|
||||||
): Promise<AxiosResponse<Response>> => {
|
|
||||||
return axios.options<Response>(url, config);
|
|
||||||
},
|
|
||||||
post: <Query, Body, Response>(
|
|
||||||
url: string,
|
|
||||||
body: Body,
|
|
||||||
config: RequestConfig<Query>
|
|
||||||
): Promise<AxiosResponse<Response>> => {
|
|
||||||
return axios.post<Response>(url, body, config);
|
|
||||||
},
|
|
||||||
put: <Query, Body, Response>(
|
|
||||||
url: string,
|
|
||||||
body: Body,
|
|
||||||
config: RequestConfig<Query>
|
|
||||||
): Promise<AxiosResponse<Response>> => {
|
|
||||||
return axios.post<Response>(url, body, config);
|
|
||||||
},
|
|
||||||
patch: <Query, Body, Response>(
|
|
||||||
url: string,
|
|
||||||
body: Body,
|
|
||||||
config: RequestConfig<Query>
|
|
||||||
): Promise<AxiosResponse<Response>> => {
|
|
||||||
return axios.post<Response>(url, body, config);
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|||||||
20
src/core/utils/makeApi.ts
Normal file
20
src/core/utils/makeApi.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import {fromPromise} from '@most/core';
|
||||||
|
import {Stream} from '@most/types';
|
||||||
|
import {objectEntries} from './objectEntries';
|
||||||
|
|
||||||
|
type PromiseApi = Record<string, (...args: any[]) => Promise<unknown>>;
|
||||||
|
|
||||||
|
type StreamApi<T extends PromiseApi> = {
|
||||||
|
[K in keyof T]: (...params: Parameters<T[K]>) => (
|
||||||
|
T[K] extends (...args: any[]) => Promise<infer R> ? Stream<R> : never
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const makeApi = <T extends PromiseApi>(apiObj: T) => {
|
||||||
|
return objectEntries(apiObj).reduce((streamObj, [apiKey, apiMethod]) => {
|
||||||
|
return {
|
||||||
|
...streamObj,
|
||||||
|
[apiKey]: (...args: Parameters<typeof apiMethod>) => fromPromise(apiMethod(...args)),
|
||||||
|
};
|
||||||
|
}, {} as StreamApi<T>);
|
||||||
|
};
|
||||||
@ -1,8 +1,18 @@
|
|||||||
import React, {memo} from 'react';
|
import React, {memo} from 'react';
|
||||||
|
import {usersApi} from '../../../../core/api/usersTestApi';
|
||||||
|
import {useStream} from '../../../../core/utils/useStream';
|
||||||
|
|
||||||
|
const userList$ = usersApi.request();
|
||||||
|
|
||||||
const Page: React.FC = () => {
|
const Page: React.FC = () => {
|
||||||
|
const users = useStream(userList$, []);
|
||||||
return (
|
return (
|
||||||
<div>tags</div>
|
<div>
|
||||||
|
tags
|
||||||
|
{users.map(user => (
|
||||||
|
<div key={user.id}>{user.first_name}, {user.last_name}</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user