2.1 KiB
2.1 KiB
Infrastructure Layer
App-wide technical adapters connecting the app to technical systems and shared runtime services: HTTP clients and interceptors, shared React Query helpers (keys, response types, error normalization), storage/browser adapters, formatting service adapters, technical config wrappers. No feature business logic.
infrastructure/
├── axios/
│ ├── index.ts # configured axios client
│ ├── interceptors.ts # request/response interceptors
│ └── axios.d.ts # axios type augmentation
│
├── reactQuery/
│ ├── index.ts
│ ├── errors.ts # query error handling helpers
│ ├── helpers.ts # query key and pagination helpers
│ ├── queryParams.ts # table/query-param mapping helpers
│ └── types.ts # shared API response/query types
│
├── IntlDate.ts # date formatting service adapter
└── IntlName.ts # name formatting service adapter
Rules
- Feature-agnostic: no module business rules, no page/component composition, no entity mapping that belongs in a module
data/mapper. - API modules use infrastructure clients (
import { axiosClient } from "#infrastructure/axios") instead of creating their own. - React Query helpers shared across modules (key builders, list response types, pagination, error extraction) live here.
- UI never calls raw HTTP clients — view/page code uses data-layer hooks; direct
#infrastructure/axiosusage belongs in API/data modules. - Generic formatting adapters (
IntlDate,IntlName) may be consumed by UI. - Keep app-state coupling narrow — prefer dependency injection; don't import feature modules into infrastructure.
Examples
import { axiosClient } from "#infrastructure/axios";
export class UserAPI {
getDetailed(id: number) {
return axiosClient.get(`/users/${id}`).then((response) => response.data);
}
}
import {
createKeyBuilder,
getPaginationInfo,
} from "#infrastructure/reactQuery";
export const usersCacheKey = createKeyBuilder("USERS", "LIST");