Repository: reduxjs/redux-toolkit

Problem statement:
Question/Feature (@rtk-query/codegen-openapi): Support for overriding path-level parameters at operation Level
Hey.
I was trying to set up my query client with the auto generator and noticed that the generated `ApiArg` types are not following the OpenAPI specs for overriding path-level parameters. At least not how I would expect them to.

From the OpenAPI specs on operation object parameters: https://spec.openapis.org/oas/latest.html#operation-object
> A list of parameters that are applicable for this operation. **If a parameter is already defined at the [Path Item](https://spec.openapis.org/oas/latest.html#pathItemParameters), the new definition will override it but can never remove it.** 

An OpenAPI spec example of this from https://swagger.io/docs/specification/describing-parameters/
```yaml
paths:
  /users/{id}:
    parameters:
      - in: path
        name: id
        type: integer
        required: true
        description: The user ID.
        
    # DELETE /users/{id} - uses a single ID.
    # Reuses the {id} parameter definition from the path level.
    delete:
      summary: Deletes the user with the specified ID.
      responses:
        '204':
          description: User was deleted.
    # GET /users/id1,id2,id3 - uses one or more user IDs.
    # Overrides the path-level {id} parameter.
    get:
      summary: Gets one or more users by ID.
      parameters:
        - in: path
          name: id
          required: true
          description: A comma-separated list of user IDs.
          type: array
          items:
            type: integer
          minItems: 1
      responses:
        '200':
          description: OK
```

Which results in the generated `ApiArgs`
```typescript
export type DeleteUsersByIdApiArg = {
  /** The user ID. */
  id: number;
};
export type GetUsersByIdApiArg = {
  /** The user ID. */
  pathId: number;
  /** A comma-separated list of user IDs. */
  _pathId: number[];
};
```

It looks good when not overriding the path-level parameter, but overriding the parameter at operation-level, the generated `id` path-level parameter is now present twice - as both types.
Both of these different parameters then has to be provided in the hooks, which seems odd and makes the querying quite confusing. Is this intended?
![image](https://github.com/reduxjs/redux-toolkit/assets/109796353/8d25474c-02fa-438f-ba41-f384f9d5b67c)

I would expect the generated `ApiArgs` to match those of the OpenAPI specs and only require the overriding parameter. Like we see in the swagger UI, only requiring operation-level parameter.
![image](https://github.com/reduxjs/redux-toolkit/assets/109796353/d12ce0e5-7cc1-4cb8-b0f8-123f5a4f13fa)

Any clarification would be appreciated, thanks.




Hints:

Patch:
diff --git a/packages/rtk-query-codegen-openapi/src/generate.ts b/packages/rtk-query-codegen-openapi/src/generate.ts
--- a/packages/rtk-query-codegen-openapi/src/generate.ts
+++ b/packages/rtk-query-codegen-openapi/src/generate.ts
@@ -278,10 +278,14 @@ export async function generateApi(
       ).name
     );
 
-    const parameters = supportDeepObjects([
-      ...apiGen.resolveArray(pathItem.parameters),
-      ...apiGen.resolveArray(operation.parameters),
-    ]).filter(argumentMatches(overrides?.parameterFilter));
+    const operationParameters = apiGen.resolveArray(operation.parameters);
+    const pathItemParameters = apiGen
+      .resolveArray(pathItem.parameters)
+      .filter((pp) => !operationParameters.some((op) => op.name === pp.name && op.in === pp.in));
+
+    const parameters = supportDeepObjects([...pathItemParameters, ...operationParameters]).filter(
+      argumentMatches(overrides?.parameterFilter)
+    );
 
     const allNames = parameters.map((p) => p.name);
     const queryArg: QueryArgDefinitions = {};


Test patch:
diff --git a/packages/rtk-query-codegen-openapi/test/__snapshots__/generateEndpoints.test.ts.snap b/packages/rtk-query-codegen-openapi/test/__snapshots__/generateEndpoints.test.ts.snap
--- a/packages/rtk-query-codegen-openapi/test/__snapshots__/generateEndpoints.test.ts.snap
+++ b/packages/rtk-query-codegen-openapi/test/__snapshots__/generateEndpoints.test.ts.snap
@@ -2524,6 +2524,24 @@ export type ExampleSchemaWrite = {
 "
 `;
 
+exports[`query parameters > parameters overridden in swagger should also be overridden in the code 1`] = `
+"import { api } from "./fixtures/emptyApi";
+const injectedRtkApi = api.injectEndpoints({
+  endpoints: (build) => ({
+    getUsersById: build.query<GetUsersByIdApiResponse, GetUsersByIdApiArg>({
+      query: (queryArg) => ({ url: \`/users/\${queryArg.id}\` }),
+    }),
+  }),
+  overrideExisting: false,
+});
+export { injectedRtkApi as enhancedApi };
+export type GetUsersByIdApiResponse = unknown;
+export type GetUsersByIdApiArg = {
+  id: number;
+};
+"
+`;
+
 exports[`should use brackets in a querystring urls arg, when the arg contains full stops 1`] = `
 "import { api } from "./fixtures/emptyApi";
 const injectedRtkApi = api.injectEndpoints({
diff --git a/packages/rtk-query-codegen-openapi/test/fixtures/parameterOverride.yaml b/packages/rtk-query-codegen-openapi/test/fixtures/parameterOverride.yaml
new file mode 100644
--- /dev/null
+++ b/packages/rtk-query-codegen-openapi/test/fixtures/parameterOverride.yaml
@@ -0,0 +1,23 @@
+openapi: 3.0.2
+info:
+  title: parameterOverride
+  version: 1.0.0
+paths:
+  /users/{id}:
+    parameters:
+      - in: path
+        name: id
+        schema:
+          type: string
+        required: true
+    get:
+      summary: Gets one or more users by ID.
+      parameters:
+        - in: path
+          name: id
+          required: true
+          schema:
+            type: integer
+      responses:
+        '200':
+          description: OK
diff --git a/packages/rtk-query-codegen-openapi/test/generateEndpoints.test.ts b/packages/rtk-query-codegen-openapi/test/generateEndpoints.test.ts
--- a/packages/rtk-query-codegen-openapi/test/generateEndpoints.test.ts
+++ b/packages/rtk-query-codegen-openapi/test/generateEndpoints.test.ts
@@ -563,3 +563,13 @@ describe('openapi spec', () => {
     expect(api).toMatchSnapshot();
   });
 });
+
+describe('query parameters', () => {
+  it('parameters overridden in swagger should also be overridden in the code', async () => {
+    const api = await generateEndpoints({
+      schemaFile: './test/fixtures/parameterOverride.yaml',
+      apiFile: './fixtures/emptyApi.ts',
+    });
+    expect(api).toMatchSnapshot();
+  });
+});