Decklar api integration
Skill Roambee/claude-code-standards/skills/decklar-api-integration
Use when implementing API integration patterns in Decklar microfrontend apps. Covers endpoint constants, Query Key Factory, service layer, React Query hooks with caching, page-level composed hooks, error handling, and loading states.From its SKILL.md
npx -y skills add Roambee/claude-code-standards --skill decklar-api-integrationAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
12.9 KB, as published. Nobody here has run it
Decklar API Integration Skill
Use this skill whenever you are building or editing API integration code in any Decklar microfrontend app. It covers the full layered architecture — from URL constants through to page-level composed hooks — applied consistently across all modules.
When to trigger this skill
Trigger this skill when the user asks to:
- implement API calls for any feature or module
- add a new endpoint integration (GET / POST / PUT / DELETE)
- connect a form or page to backend APIs
- add caching, deduplication, or React Query to data fetching
- build or refactor query hooks, service functions, or mutation handlers
- wire filter state into a paginated table
Architecture Layers (read in order)
Every API integration follows this strict separation of concerns:
| Layer | File location | Single responsibility |
|---|---|---|
endpoints.ts | src/api/endpoints.ts | URL strings only |
queryKeys.ts | src/api/queryKeys.ts | Cache key shapes only |
*.service.ts | src/api/services/ | Raw API calls — pure async functions |
| Base query hooks | src/api/hooks/use<Resource>.ts | Wire service → React Query — no logic |
| Filter state hooks | src/api/hooks/use<Resource>Filters.ts | Simple local filter — useState only, no queries. Omit when using useUrlFilters. |
| Page-level hooks | src/api/hooks/use<Resource>Page.ts | Compose all layers + side effects. Call useUrlFilters here when URL persistence is required. |
utils/validations.ts | src/utils/ | Pure validation / transform functions |
| Components | — | UI only — call one page hook |
Golden rule: Components call one page hook and get back everything they need. No useEffect for data fetching. No API calls inside components.
Canonical Folder Structure
src/
├── api/ # EVERYTHING non-UI lives here
│ ├── endpoints.ts # All URL constants (BASE_URL + ENDPOINTS)
│ ├── queryKeys.ts # All React Query cache key factories
│ ├── hooks/
│ │ ├── useResource.ts # Base query + mutation hooks — one file per resource
│ │ ├── useResourceFilters.ts # Local filter useState only — omit when using useUrlFilters
│ │ └── useResourcePage.ts # Page-level composed hook — assembles all layers; call useUrlFilters here
│ └── services/
│ ├── resource.service.ts # Pure async API functions — one file per resource
│ ├── filterOptions.service.ts
│ └── index.ts # Re-exports all services
├── components/ # UI only — import from src/api/hooks/
│ └── <Feature>/
│ ├── index.ts # Re-exports
│ ├── types.ts # Shared TypeScript types/interfaces for this feature
│ ├── constants.ts # Static dropdown options, badge maps, status enums
│ └── components/
│ ├── Home/index.tsx
│ ├── Form/index.tsx
│ └── Detail/index.tsx
├── routes/
├── root.component.tsx # QueryClient + QueryClientProvider lives here
└── utils/
└── resource.validations.ts # Pure validation/transform functions
QueryClientProviderplacement: For Single-SPA microfrontends, defineQueryClientinline inroot.component.tsx— no need for a separatelib/queryClient.ts. Wrap<BrowserRouter>inside<QueryClientProvider>.
src/api/is the only non-component folder. There is nosrc/hooks/orsrc/constants/folder. Local filter hooks (useResourceFilters.ts, when not usinguseUrlFilters) and page-level composed hooks (useResourcePage.ts) both live insrc/api/hooks/alongside the base query hooks. Components only import fromsrc/api/hooks/.
Reference Files
Load the relevant reference file when implementing each concern:
- URL-persisted filters for data tables (3-layer pattern) — start here when adding filters to any table → references/url-filter-datatable.md
- React Query hooks (QueryClient config, Query Key Factory, service layer, base hooks, mutation hooks, page-level composed hooks,
selecttransforms) → references/react-query-hooks.md - API integration flow (endpoint constants, API wrapper, mutations, breadcrumbs) → references/api-flow.md
- Filter layout (grid rules, multi-column examples) → references/filter-layout.md
- Table & mutation conventions (shared hooks, table action columns, applied-filter pattern,
useUrlFilters) → references/table-conventions.md - Advanced patterns (OData query building, conditional validation, tab routing, route state passing, URL-persisted filters) → references/advanced-patterns.md
Starter Templates
When creating a new resource integration, copy and adapt from assets/:
- Full resource template → assets/query-hook-template.ts — endpoints → queryKeys → service → base hooks → page hook
- URL-filter page hook → assets/url-filter-page-hook-template.ts —
useResourcePage.tsready to copy, withuseUrlFilters+ date bridge - URL-filter service snippet → assets/url-filter-service-snippet.ts —
buildFilterQuery()OData builder ready to copy
Quick API integration checklist
- URL constant added to
src/api/endpoints.tsusingBASE_URLfor/v2/routes — never write URL strings in hooks - Cache key added to
src/api/queryKeys.tsusing the hierarchical factory pattern (.all/.lists()/.list(filters)/.detail(id)) - Service function created in
src/api/services/<resource>.service.ts— pure async, no React, no hooks - Base query/mutation hooks created in
src/api/hooks/use<Resource>.ts— wire service → React Query, no business logic - Filter state: choose one approach:
- URL-persisted (preferred for paginated tables): call
useUrlFilters<T>(searchParams, setSearchParams, { defaults, keys })from@decklar/client-utilityinside the page hook — no separateFilters.tsfile needed - Local only (simple forms / non-navigable state): create
src/api/hooks/use<Resource>Filters.tswith plainuseState— no queries inside
- URL-persisted (preferred for paginated tables): call
- Page-level composed hook created in
src/api/hooks/use<Resource>Page.ts— assembles base hooks + filters + side effects - GET data fetching uses
useQueryinsrc/api/hooks/— NOT a rawuseEffectin any component - Multiple components sharing the same data use the same query key (no duplicate fetches)
-
QueryClientProvideris present inroot.component.tsx - Mutations (POST/PUT/DELETE) use
useMutationand callinvalidateQueries/setQueryDatainonSuccess -
isFetchingused for inline overlay spinner;isLoadingonly for full-page skeleton (first load) - Paginated tables use
placeholderData: keepPreviousDatato prevent blank-flash on page change - Filter inputs use "applied filters" pattern — query only updates on "Apply" click, not on every keystroke
- Filter state lives in
src/api/hooks/use<Resource>Filters.ts— not inline in the component - Validation/transform logic lives in
src/utils/resource.validations.ts— pure functions, called from page hooks - Error handling uses
EventEmitter.emit('showSnackbar', {...})or Modal - UI uses
@decklar/ui-librarycomponents only — no raw HTML primitives - Submit button is
disabled={isPending}while mutation is in flight - Table row actions use
getRowActions+TableActionMenuItem[]— never inline<Button>cell - Filter dropdown options (roles, statuses, categories) are their own query with
staleTime: Infinity - Page components call one page-level hook — zero API logic in the component body
- TypeScript types/interfaces for the feature live in
components/<Feature>/types.ts - Static constants (dropdown options, badge maps, status enums) live in
components/<Feature>/constants.ts
Common Mistakes to Avoid
| ❌ Wrong | ✅ Correct |
|---|---|
useEffect(() => { fetch('/v2/items').then(...) }, []) in a component | Base query hook in src/api/hooks/ |
URL string /v2/items written directly in a hook | ENDPOINTS.ITEMS.LIST from src/api/endpoints.ts |
API call logic (API(), getAuthUser(), URL building) inline in queryFn | Move all of that to src/api/services/*.service.ts |
API_PATH or any legacy URL config file alongside endpoints.ts | Delete the old file — one source of truth: endpoints.ts |
Business logic (if data.length === 0 navigate(...)) inside a base query hook | Move to src/api/hooks/use<Resource>Page.ts |
useQuery({ queryKey: ['items', 'list'] }) as a raw string array | queryKeys.items.lists() from src/api/queryKeys.ts |
Any hook (useQuery, useMutation, filter useState) in src/hooks/ directly | Move to src/api/hooks/ — src/hooks/ folder must not exist |
Filter useState inline in a component | src/api/hooks/use<Resource>Filters.ts (local) or useUrlFilters inside the page hook (URL-persisted) |
useUrlFilters called directly in a component | Move useSearchParams() + useUrlFilters() to src/api/hooks/use<Resource>Page.ts |
Page hook in src/hooks/ importing from src/api/hooks/ | Put it directly in src/api/hooks/use<Resource>Page.ts |
const [loading, setLoading] = useState(false) + manual try/catch for mutations | useMutation with isPending |
Validation logic (items.some(...)) inside a component or page hook | Move to src/utils/resource.validations.ts |
When to use this skill vs decklar-ui-library
- Use
decklar-ui-libraryfor component selection, form layout, and UI details. - Use
decklar-api-integrationwhen wiring backend APIs, building payloads, and handling network flow.
Trigger phrases for this skill
- "Add API integration for [any module/page]"
- "Implement POST / PUT / DELETE API call"
- "Connect form submit to backend API"
- "Load list from API in a page"
- "Add caching to API calls"
- "Use React Query for data fetching"
- "Table data loading is slow, add caching"
- "Add filter state to a paginated table" / "persist filters in URL"
- "Create a service layer for [resource]"
- "Add a query key factory for [resource]"