Skip to content

Commit

Permalink
Merge pull request #4189 from ffluk3/throw-on-override
Browse files Browse the repository at this point in the history
Provide 'throw' option for `overrideExisting`
  • Loading branch information
EskiMojo14 authored Feb 12, 2024
2 parents 0ab713e + a060b45 commit a89db66
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 5 deletions.
9 changes: 8 additions & 1 deletion docs/rtk-query/api/created-api/code-splitting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,14 @@ const injectEndpoints = (endpointOptions: InjectedEndpointOptions) =>

interface InjectedEndpointOptions {
endpoints: (build: EndpointBuilder) => NewEndpointDefinitions
overrideExisting?: boolean
/**
* Optionally allows endpoints to be overridden if defined by multiple `injectEndpoints` calls.
*
* If set to `true`, will override existing endpoints with the new definition.
* If set to `'throw'`, will throw an error if an endpoint is redefined with a different definition.
* If set to `false` (or unset), will not override existing endpoints with the new definition, and log a warning in development.
*/
overrideExisting?: boolean | 'throw'
}
```

Expand Down
4 changes: 3 additions & 1 deletion docs/rtk-query/usage/code-splitting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,7 @@ export const { useExampleQuery } = extendedApi
```

:::tip
If you inject an endpoint that already exists and don't explicitly specify `overrideExisting: true`, the endpoint will not be overridden. In development mode, you will get a warning about this.
If you inject an endpoint that already exists and don't explicitly specify `overrideExisting: true`, the endpoint
will not be overridden. In development mode, you will get a warning about this if `overrideExisting` is set to `false`,
and an error will be throw if set to `'throw'`.
:::
9 changes: 8 additions & 1 deletion packages/toolkit/src/query/apiTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,14 @@ export type Api<
endpoints: (
build: EndpointBuilder<BaseQuery, TagTypes, ReducerPath>,
) => NewDefinitions
overrideExisting?: boolean
/**
* Optionally allows endpoints to be overridden if defined by multiple `injectEndpoints` calls.
*
* If set to `true`, will override existing endpoints with the new definition.
* If set to `'throw'`, will throw an error if an endpoint is redefined with a different definition.
* If set to `false` (or unset), will not override existing endpoints with the new definition, and log a warning in development.
*/
overrideExisting?: boolean | 'throw'
}): Api<
BaseQuery,
Definitions & NewDefinitions,
Expand Down
8 changes: 6 additions & 2 deletions packages/toolkit/src/query/createApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,10 +353,14 @@ export function buildCreateApi<Modules extends [Module<any>, ...Module<any>[]]>(
evaluatedEndpoints,
)) {
if (
!inject.overrideExisting &&
inject.overrideExisting !== true &&
endpointName in context.endpointDefinitions
) {
if (
if (inject.overrideExisting === 'throw') {
throw new Error(
`called \`injectEndpoints\` to override already-existing endpointName ${endpointName} without specifying \`overrideExisting: true\``,
)
} else if (
typeof process !== 'undefined' &&
process.env.NODE_ENV === 'development'
) {
Expand Down
86 changes: 86 additions & 0 deletions packages/toolkit/src/query/tests/injectEndpoints.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
import { vi } from 'vitest'

const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }),
endpoints: () => ({}),
})

describe('injectEndpoints', () => {
test("query: overridding with `overrideEndpoints`='throw' throws an error", async () => {
const extended = api.injectEndpoints({
endpoints: (build) => ({
injected: build.query<unknown, string>({
query: () => '/success',
}),
}),
})

expect(() => {
extended.injectEndpoints({
overrideExisting: 'throw',
endpoints: (build) => ({
injected: build.query<unknown, string>({
query: () => '/success',
}),
}),
})
}).toThrowError(
new Error(
`called \`injectEndpoints\` to override already-existing endpointName injected without specifying \`overrideExisting: true\``,
),
)
})

test('query: overridding an endpoint with `overrideEndpoints`=false does nothing in production', async () => {
const consoleMock = vi.spyOn(console, 'error').mockImplementation(() => {})

process.env.NODE_ENV = 'development'

const extended = api.injectEndpoints({
endpoints: (build) => ({
injected: build.query<unknown, string>({
query: () => '/success',
}),
}),
})

extended.injectEndpoints({
overrideExisting: false,
endpoints: (build) => ({
injected: build.query<unknown, string>({
query: () => '/success',
}),
}),
})

expect(consoleMock).toHaveBeenCalledWith(
`called \`injectEndpoints\` to override already-existing endpointName injected without specifying \`overrideExisting: true\``,
)
})

test('query: overridding with `overrideEndpoints`=false logs an error in development', async () => {
const consoleMock = vi.spyOn(console, 'error').mockImplementation(() => {})

process.env.NODE_ENV = 'production'

const extended = api.injectEndpoints({
endpoints: (build) => ({
injected: build.query<unknown, string>({
query: () => '/success',
}),
}),
})

extended.injectEndpoints({
overrideExisting: false,
endpoints: (build) => ({
injected: build.query<unknown, string>({
query: () => '/success',
}),
}),
})

expect(consoleMock).not.toHaveBeenCalled()
})
})

0 comments on commit a89db66

Please sign in to comment.