Response Builder
- import:
@azure-net/kit/infra - Preferred location (for base shared responses):
src/app/core/responses - Preferred location (for context):
src/app/contexts/{ContextName}/infrastructure/http/responses
Построитель ответов с поддержкой маппинга, извлечения данных и добавления метаданных, подстраивает всю систему ответов под единую, избавляя от постоянных распаковок data.data и извлечения данных, требуемых для ответа, из заголовков и других ключей.
Основное использование
Ниже представлено базовое использование этого класса без наследования и интеграции с источником данных. Для изучения методов рекомендуется интеграция с Datasource по примерам в следующем разделе.
typescript
import { ResponseBuilder } from '@azure-net/kit/infra';
// Создание из HTTP ответа
const response = await httpService.get<User[]>('/users');
const builder = new ResponseBuilder(response);
// Получение данных
const data = builder.getData(); // User[] - просто получает data из ответа
const full = builder.get(); // { data: User[], meta: {} } - получает data и метаданные
const flatten = builder.getFlatten(); // { data: User[], ...meta }
const raw = builder.getRaw(); // HttpServiceResponse - отдает голый ответ от http-сервиса
// Добавление метаданных (автотипизация)
const withMeta = builder.addMeta({
totalCount: 100,
currentPage: 1
});
console.log(withMeta.get());
// { data: User[], meta: { totalCount: 100, currentPage: 1 } }Расширенное использование
typescript
import { ResponseBuilder } from '$lib/core/infra/index.js';
// То, что нам присылает бэкенд, всегда в одном формате, например:
export interface IBackendApiDataSourceResponse<T = unknown> {
data: T;
success: boolean;
message: string;
}
// TData и TMeta мы не трогаем, так как они нужны для типизации дженериками ответов с бэка.
// Третий дженерик — это случай, когда бэк посылает нам ответ в обёртке, которую мы хотим распаковать заранее
export class CustomApiResponse<TData = unknown, TMeta = unknown> extends ResponseBuilder<TData, TMeta, IBackendApiDataSourceResponse<TData>> {
// override метода unwrapData позволяет нам распаковывать данные из обёртки, возвращает чистую data
override unwrapData(data: IBackendApiDataSourceResponse<TData>): TData {
return data.data;
}
// Кастомный метод, добавляющий во все ответы возможность добавить метаданные, например извлечь заранее пагинацию из ответа и поместить её в мету
// Использование данного метода автоматически типизирует мету под то, что у нас возвращается
// Таких методов может быть сколько угодно
paginate() {
return this.addMeta({ page: Number(this.response.data.data.meta.page), total: Number(this.response.data.data.meta.total) });
}
}
// Базовый пример использования, рекомендуется интеграция через datasource по примерам в следующем разделе
const paginatedResponse = new CustomApiResponse(response).paginate().get(); //{data: typeof response, meta: {page: number, total: number;}}Маппинг с ресурсами (пример с использованием CustomApiResponse из раздела Расширенное использование выше)
typescript
interface IUser {
id: number;
name: string;
email: string;
}
interface IMappedUser {
id: number;
firstName: string;
lastName: string;
email: string;
status: number;
fullName: string;
}
// Создание класса-маппера
class UserDTO extends DTOMapper<IMappedUser> {
id: number;
name: string;
lastName: string;
email: string;
status: number;
fullName: string;
constructor(data: IUser) {
super();
this.id = data.id;
this.name = data.name;
this.lastName = 'SomeTestLastname';
this.email = data.email;
this.status = 1;
// все обработки вызываем в конструкторе
this.fullName = this.getFullName();
}
getFullName() {
return `${this.name} ${this.lastName}`;
}
}
// Маппинг одиночного объекта
const userBuilder = new CustomApiResponse(response);
const mappedUser = userBuilder.mapUsing(UserDTO).getData(); // IMappedUser
// Маппинг коллекции
const usersResponse = await httpService.get<User[]>('/users');
const usersBuilder = new CustomApiResponse(usersResponse);
const mappedUsers = usersBuilder.paginate().mapCollectionUsing(UserDTO).get(); //{data: IMappedUser[], meta: {page: number, total: number;}}Извлечение вложенных данных
typescript
interface ILoginResponse {
token: string;
type: 'Bearer';
expires: {
at: string;
}
}
const response = await httpService.post<ILoginResponse>('/login', {json: someJson});
const builder = new ResponseBuilder(response);
// Извлечь только токен из ответа и вернуть в data
const users = builder.extract('token').getData(); // string;
// Извлечение вложенного значения
const total = builder.extract('expires.at'); // string ILoginResponse['expires']['at']