Frontend-to-backend integration
Treat the backend contract, client abstraction, and UI state lifecycle as one flow. Reuse the nearest working feature before adding a new service or state layer.
Trace the existing pattern
Inspect:
- The backend route's method, mounted path, inputs, authentication, and response shape.
- The shared frontend HTTP client and its base URL, headers, serialization, cancellation, and error normalization.
- A comparable service function.
- The component, hook, query library, store, or context that owns similar state.
- Tests or mocks that define the client contract.
Do not assume the frontend mirrors backend directories or requires a hook/context pair. Follow the architecture already in use.
Implement the client boundary
Keep endpoint details in the established service or generated-client layer rather than scattering URLs through components.
A service function should make its inputs and result contract clear:
export async function updateResource(input: UpdateResourceInput, options?: RequestOptions) {
return client.patch(`/resources/${input.id}`, input.changes, options);
}
Adapt the example to local conventions. In particular:
- Build paths from the actual mounted route.
- Put credentials or session headers in the shared client, not individual calls, unless the project requires otherwise.
- Preserve the project's success/error representation.
- Support cancellation or request identity when stale responses are possible.
- Avoid leaking transport-specific details beyond the service boundary.
Choose the smallest state owner
Use the narrowest existing mechanism that fits:
- Component state for local, short-lived interaction.
- A custom hook for reusable behavior or lifecycle logic.
- A query/cache library for server state when the project already uses one.
- Context or a store only when state must be shared across a meaningful subtree or application boundary.
Do not create a context, provider, reducer, or global store solely because an API call was added.
Handle lifecycle and races
- Represent loading, success, empty, and failure states intentionally.
- Prevent stale requests from overwriting newer state.
- Clean up subscriptions and cancel requests when supported.
- Keep effect dependencies accurate; do not suppress warnings to hide unstable design.
- Use optimistic updates only when rollback and conflict behavior are defined.
- Invalidate or update the correct cache entries after mutations.
Translate technical errors into the project's user-facing error system without discarding diagnostic context needed by logs or tests.
Verify the integration
Test the layers that carry real risk:
- Service method, path, payload, and headers.
- Success and normalized failure handling.
- Loading and stale-response behavior.
- Cache invalidation or shared-state propagation.
- The consuming UI's important success and error states.
Run focused frontend tests and type/lint checks. When practical, verify the call against the actual backend route rather than relying only on a mock with a separately invented contract.
1---2name: frontend-backend-call3description: Connect a frontend feature to a backend endpoint while preserving the project's API client, response contract, state ownership, caching, and error handling. Use when adding or changing client services, React hooks, query integrations, contexts, or consuming components.4---56# Frontend-to-backend integration78Treat the backend contract, client abstraction, and UI state lifecycle as one flow. Reuse the nearest working feature before adding a new service or state layer.910## Trace the existing pattern1112Inspect:13141. The backend route's method, mounted path, inputs, authentication, and response shape.152. The shared frontend HTTP client and its base URL, headers, serialization, cancellation, and error normalization.163. A comparable service function.174. The component, hook, query library, store, or context that owns similar state.185. Tests or mocks that define the client contract.1920Do not assume the frontend mirrors backend directories or requires a hook/context pair. Follow the architecture already in use.2122## Implement the client boundary2324Keep endpoint details in the established service or generated-client layer rather than scattering URLs through components.2526A service function should make its inputs and result contract clear:2728```ts29export async function updateResource(input: UpdateResourceInput, options?: RequestOptions) {30 return client.patch(`/resources/${input.id}`, input.changes, options);31}32```3334Adapt the example to local conventions. In particular:3536- Build paths from the actual mounted route.37- Put credentials or session headers in the shared client, not individual calls, unless the project requires otherwise.38- Preserve the project's success/error representation.39- Support cancellation or request identity when stale responses are possible.40- Avoid leaking transport-specific details beyond the service boundary.4142## Choose the smallest state owner4344Use the narrowest existing mechanism that fits:4546- Component state for local, short-lived interaction.47- A custom hook for reusable behavior or lifecycle logic.48- A query/cache library for server state when the project already uses one.49- Context or a store only when state must be shared across a meaningful subtree or application boundary.5051Do not create a context, provider, reducer, or global store solely because an API call was added.5253## Handle lifecycle and races5455- Represent loading, success, empty, and failure states intentionally.56- Prevent stale requests from overwriting newer state.57- Clean up subscriptions and cancel requests when supported.58- Keep effect dependencies accurate; do not suppress warnings to hide unstable design.59- Use optimistic updates only when rollback and conflict behavior are defined.60- Invalidate or update the correct cache entries after mutations.6162Translate technical errors into the project's user-facing error system without discarding diagnostic context needed by logs or tests.6364## Verify the integration6566Test the layers that carry real risk:67681. Service method, path, payload, and headers.692. Success and normalized failure handling.703. Loading and stale-response behavior.714. Cache invalidation or shared-state propagation.725. The consuming UI's important success and error states.7374Run focused frontend tests and type/lint checks. When practical, verify the call against the actual backend route rather than relying only on a mock with a separately invented contract.