3.1 KiB
Infrastructure Layer
Table of Contents
Purpose
The infrastructure/ layer contains app-wide technical adapters and integration helpers.
Use this layer for code that connects the frontend application to technical systems or shared runtime services, not for feature-specific business logic.
Responsibilities
The infrastructure/ layer is responsible for:
- HTTP clients and request/response interceptors
- React Query shared helpers, response types, query key helpers, and error normalization
- storage, browser, or runtime adapters
- shared formatting/service adapters such as date or name formatting services
- app-wide technical configuration wrappers
Recommended Structure
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
-
Keep infrastructure feature-agnostic.
- No module-specific business rules
- No page or component composition
- No entity mapping that belongs in a module
data/mapper
-
API modules should use infrastructure clients instead of creating their own clients.
import { axiosClient } from "#infrastructure/axios"; -
React Query helpers that are shared across modules belong here.
Examples: query key builders, list response types, pagination helpers, error extraction helpers.
-
UI layers must not call raw HTTP clients directly.
View and page code should call data-layer hooks. Direct
#infrastructure/axiosusage belongs in API/data modules, not in components. -
Generic formatting adapters may be consumed by UI when they are not tied to a feature.
Examples:
IntlDate,IntlName. -
Prefer dependency injection for app-state coupling.
If an interceptor needs auth or query-client behavior, keep that coupling narrow and documented. Avoid importing random feature modules into infrastructure.
Examples
API modules use the configured HTTP client:
import { axiosClient } from "#infrastructure/axios";
export class UserAPI {
getDetailed(id: number) {
return axiosClient.get(`/users/${id}`).then((response) => response.data);
}
}
Data/query modules use shared query helpers:
import {
createKeyBuilder,
getPaginationInfo,
} from "#infrastructure/reactQuery";
export const usersCacheKey = createKeyBuilder("USERS", "LIST");
UI can consume generic app-wide formatters:
import { IntlDate } from "#infrastructure/IntlDate";