Skip to content

Codegen OpenAPI translates anyOf number/integer to any type #3648

@saschahofmann

Description

@saschahofmann

In my OpenAPI schema I have a schema type defined as

{
  "Coordinates": {
    "prefixItems": [
      {
        "anyOf": [
          {
            "type": "number"
          },
          {
            "type": "integer"
          }
        ],
        "title": "Lon"
      },
      {
        "anyOf": [
          {
            "type": "number"
          },
          {
            "type": "integer"
          }
        ],
        "title": "Lat"
      }
    ],
    "type": "array",
    "maxItems": 2,
    "minItems": 2
  }
}

which I would expect to be read as

type Coordinates = [number, number]

but instead I receive

type Coordinates = any;

More details

I am running an API using FastAPI, I generate the OpenAPI schema using the inbuilt method which produces a schema with "openapi": "3.1.0". I then use rtk-query-codegen-openapi to create my frontend client.

Reproducible example

Given this openapi.json

{
  "openapi": "3.1.0",
  "info": {
    "title": "Test",
    "description": "",
    "version": "1.0.0"
  },
  "paths": {
    "/test/": {
      "get": {
        "summary": "",
        "description": "",
        "operationId": "get_test",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Coordinates"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Coordinates": {
        "prefixItems": [
          {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "integer"
              }
            ],
            "title": "Lon"
          },
          {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "integer"
              }
            ],
            "title": "Lat"
          }
        ],
        "type": "array",
        "maxItems": 2,
        "minItems": 2
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          }
        },
        "type": "object",
        "required": ["loc", "msg", "type"],
        "title": "ValidationError"
      }
    }
  }
}

this empyApi.ts

import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";

// initialize an empty api service that we'll inject endpoints into later as needed
export const emptyApi = createApi({
  reducerPath: "api",
  baseQuery: fetchBaseQuery({
    baseUrl: "localhost",
  }),
  endpoints: () => ({}),
});

and the is openApiConfig.json

{
  "schemaFile": "openapi.json",
  "apiFile": "./emptyApi.ts",
  "apiImport": "emptyApi",
  "outputFile": "./apiClient.ts",
  "exportName": "apiClient",
  "hooks": true,
  "tag": true
}

I receive this apiClient.ts after running rtk-query-codegen-openapi openApiConfig.json

import { emptyApi as api } from "./emptyApi";
export const addTagTypes = [] as const;
const injectedRtkApi = api
  .enhanceEndpoints({
    addTagTypes,
  })
  .injectEndpoints({
    endpoints: (build) => ({
      getTest: build.query<GetTestApiResponse, GetTestApiArg>({
        query: () => ({ url: `/test/` }),
      }),
    }),
    overrideExisting: false,
  });
export { injectedRtkApi as apiClient };
export type GetTestApiResponse =
  /** status 200 Successful Response */ Coordinates;
export type GetTestApiArg = void;
export type Coordinates = any;
export type ValidationError = {
  loc: (string | number)[];
  msg: string;
  type: string;
};
export type HttpValidationError = {
  detail?: ValidationError[];
};
export const { useGetTestQuery } = injectedRtkApi;

As you can see in L19 Coordinates is typed as any.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions