Сервисы
Паттерн
Каждый сервис — это класс-синглтон, экспортируемый как единственный экземпляр:
import { clientService } from '@diealltagsfeen/frontend-api-client'Сервисы — тонкие обёртки над HTTP-клиентом пакета (http). Метод строит путь и делегирует вызов в http.get/post/put/patch/delete, который резолвит хост, проверяет контракт ответа и централизованно обрабатывает ошибки. Никакой трансформации данных в сервисах нет — ответ возвращается как есть.
Сигнатуры методов
Публичные методы — async-функции, которые:
- Принимают параметры: примитив (id), уже собранный
queryString: stringдля списков, либо типизированный объект DTO для тела запроса. - Возвращают
Promise<ApiResult<T>>— типизированный успешный ответ либоnull.
// Примитив-идентификатор
const client = await clientService.GetById(123)
// Тело запроса — типизированный DTO
await clientService.Update(updateClientRequestDto)
// Объект с несколькими полями
await clientService.UpdateStatus({ clientId: 123, status: 400 })
// Список с фильтрами — query-string собирает вызывающий код
const result = await clientService.GetTable(queryString)Построение query-string для списков
Большинство GetTable-методов принимают готовую строку запроса (queryString: string) — её формирует вызывающий код. Бэкенд ожидает поля в PascalCase (Pagination.CurrentPage, Pagination.RowsPerPage, Pagination.SortBy, Pagination.Descending, *Filters):
const params = new URLSearchParams()
params.append('Pagination.CurrentPage', String(page))
params.append('Pagination.RowsPerPage', String(rowsPerPage))
params.append('Pagination.SortBy', sortBy)
params.append('Pagination.Descending', String(descending))
statusFilters.forEach((s) => params.append('ClientStatusFilters', String(s)))
const result = await clientService.GetTable(params.toString())Часть сервисов (модуль учёта рабочего времени) принимает типизированный объект параметров и собирает query-string внутри метода — смотрите сигнатуру конкретного метода в API Reference.
Тип ответа ApiResult
type ApiResult<T> = ApiSuccess<T> | null
type ApiSuccess<T> = { successfully: true } & TУспешный ответ всегда содержит дискриминатор successfully: true и полезную нагрузку конкретного эндпоинта. Параметр-дженерик T объявляет форму ответа:
async Get(): Promise<ApiResult<GetWorkTimeSettingsResponseDto>> {
return await http.get<GetWorkTimeSettingsResponseDto>('managerTimeTracker', 'Api/WorkTimeSettings')
}Перед обращением к полям проверяйте результат на истинность — это сужает тип к ApiSuccess<T>:
const result = await workTimeSettingsAccessService.Get()
if (result) {
// result: ApiSuccess<GetWorkTimeSettingsResponseDto>
useSettings(result.settings)
}Обработка ошибок
Обработка ошибок централизована в HTTP-обёртке (http). При неуспешном ответе или сетевой ошибке она бросает исключение и вызывает колбэк onError, переданный в init():
- Тело с полем
type(RFC-7807) →ProblemDetailsError(поляtype,title,detail,data). - Прочие неуспешные ответы →
ApiError(поляhttpStatus,status,type,title,data). - Сетевая/axios-ошибка → логируется через
onErrorи пробрасывается дальше.
Сами сервисы исключения не ловят. Если нужно обработать ошибку — оборачивайте вызов в try/catch:
import { ApiError, ProblemDetailsError } from '@diealltagsfeen/frontend-api-client'
try {
const result = await clientService.Create(body)
} catch (e) {
if (e instanceof ProblemDetailsError && e.type === 'client-exists') {
// обработать конкретную бизнес-ошибку
} else if (e instanceof ApiError) {
// общая ошибка API: e.status, e.title
}
}Загрузка файлов
Методы загрузки принимают FormData и передают его как тело запроса:
const formData = new FormData()
formData.append('ClientId', String(clientId))
formData.append('Files[0].FileType', String(fileType))
formData.append('Files[0].File', file)
await clientService.AddFiles(formData)Скачивание файлов
Для бинарных ответов используется низкоуровневый метод http.blob — соответствующие сервисные методы возвращают Blob (контракт successfully не проверяется):
const blob = await datevExportAccessService.Export(queryString) // → Blob