install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/codex/redux-rtk-query-endpoints" ~/.claude/skills/intense-visions-harness-engineering-redux-rtk-query-endpoints-08d84b && rm -rf "$T"
manifest:
agents/skills/codex/redux-rtk-query-endpoints/SKILL.mdsource content
RTK Query Endpoints
Define query and mutation endpoints with cache tag invalidation, response transformation, and auto-generated hooks
When to Use
- Adding new API endpoints to an existing RTK Query service
- Implementing CRUD operations with automatic cache invalidation
- Transforming API responses before they reach components
- Setting up pagination, polling, or conditional fetching
Instructions
- Use
for read operations (GET) andbuilder.query
for write operations (POST/PUT/DELETE).builder.mutation - Provide generic type arguments:
. Usebuilder.query<ReturnType, ArgType>
when there is no argument.void - Use
on queries to declare what cache entries they populate. Use both list-level and item-level tags.providesTags - Use
on mutations to declare what cache entries to refetch after the mutation succeeds.invalidatesTags - Use
to reshape API responses before caching — extract nested data, normalize structures.transformResponse - Use
from feature modules to keep endpoints co-located with their feature code.injectEndpoints - Export the auto-generated hooks. Queries produce
anduseXQuery
; mutations produceuseLazyXQuery
.useXMutation
// features/posts/posts.api.ts import { api } from '../../services/api'; interface Post { id: string; title: string; body: string; authorId: string; } const postsApi = api.injectEndpoints({ endpoints: (builder) => ({ getPosts: builder.query<Post[], { page: number }>({ query: ({ page }) => `/posts?page=${page}`, providesTags: (result) => result ? [ ...result.map(({ id }) => ({ type: 'Post' as const, id })), { type: 'Post', id: 'LIST' }, ] : [{ type: 'Post', id: 'LIST' }], }), getPost: builder.query<Post, string>({ query: (id) => `/posts/${id}`, providesTags: (result, error, id) => [{ type: 'Post', id }], }), createPost: builder.mutation<Post, Omit<Post, 'id'>>({ query: (body) => ({ url: '/posts', method: 'POST', body }), invalidatesTags: [{ type: 'Post', id: 'LIST' }], }), updatePost: builder.mutation<Post, Pick<Post, 'id'> & Partial<Post>>({ query: ({ id, ...patch }) => ({ url: `/posts/${id}`, method: 'PATCH', body: patch }), invalidatesTags: (result, error, { id }) => [{ type: 'Post', id }], }), deletePost: builder.mutation<void, string>({ query: (id) => ({ url: `/posts/${id}`, method: 'DELETE' }), invalidatesTags: (result, error, id) => [ { type: 'Post', id }, { type: 'Post', id: 'LIST' }, ], }), }), }); export const { useGetPostsQuery, useGetPostQuery, useCreatePostMutation, useUpdatePostMutation, useDeletePostMutation, } = postsApi;
Details
Tag strategy: Use a
'LIST' sentinel ID for collection queries. Individual item queries use the actual ID. Mutations that add/remove items invalidate 'LIST' to refetch collections. Mutations that edit items invalidate only that item's tag.
transformResponse: Reshape before caching:
getUsers: builder.query<User[], void>({ query: () => '/users', transformResponse: (response: { data: User[]; meta: unknown }) => response.data, }),
Polling and refetching:
// In component const { data } = useGetPostsQuery({ page: 1 }, { pollingInterval: 30000 }); // Refetch on window focus — enabled globally via setupListeners(store.dispatch)
Pagination pattern: RTK Query caches each argument combination separately. For
page: 1 and page: 2, two cache entries exist. Use serializeQueryArgs + merge + forceRefetch for infinite scroll:
getPosts: builder.query<Post[], number>({ query: (page) => `/posts?page=${page}`, serializeQueryArgs: ({ endpointName }) => endpointName, merge: (currentCache, newItems) => { currentCache.push(...newItems); }, forceRefetch: ({ currentArg, previousArg }) => currentArg !== previousArg, }),
Source
https://redux-toolkit.js.org/rtk-query/usage/queries
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.