hey-api / openapi-ts

🚀 The OpenAPI to TypeScript codegen. Generate clients, SDKs, validators, and more. Support: @mrlubos
https://heyapi.dev
Other
1.29k stars 102 forks source link

formData: mismatch Type #497

Open m-rieke opened 6 months ago

m-rieke commented 6 months ago

Description

On creating a client for JIRA API Client (https://dac-static.atlassian.com/cloud/jira/platform/swagger-v3.v3.json?_v=1.7141.0-0.1305.0) the request for adding an attachment to a ticket has the wrong type and is not compiling.

public static addAttachment(data: $OpenApiTs['/rest/api/3/issue/{issueIdOrKey}/attachments']['post']['req']): CancelablePromise<$OpenApiTs['/rest/api/3/issue/{issueIdOrKey}/attachments']['post']['res'][200]> {
        return __request(OpenAPI, {
            method: 'POST',
            url: '/rest/api/3/issue/{issueIdOrKey}/attachments',
            path: {
                issueIdOrKey: data.issueIdOrKey
            },
            formData: data.formData,
            mediaType: 'multipart/form-data',
            errors: {
                403: 'Returned if the user does not have the necessary permission.',
                404: `Returned if any of the following is true:

 *  the issue is not found.
 *  the user does not have permission to view the issue.`,
                413: `Returned if any of the following is true:

 *  the attachments exceed the maximum attachment size for issues.
 *  more than 60 files are requested to be uploaded.
 *  the per-issue limit for attachments has been breached.

See [Configuring file attachments](https://confluence.atlassian.com/x/wIXKM) for details.`
            }
        });
    }

It fails with the following error:

Type 'MultipartFile[]' is not assignable to type 'Record<string, unknown>'. Index signature for type 'string' is missing in type 'MultipartFile[]'.

OpenAPI specification (optional)

No response

Configuration

npx @hey-api/openapi-ts -i https://dac-static.atlassian.com/cloud/jira/platform/swagger-v3.v3.json?_v=1.7141.0-0.1305.0 -o generated/src/client

System information (optional)

No response

mrlubos commented 6 months ago

Thanks again @m-rieke, will test this API and see what other issues there are with creating a build!

jordanshatford commented 6 months ago

@m-rieke I see there spec looks something like this:

      "requestBody": {
          "content": {
            "*/*": {
              "schema": {
                "items": {
                  "type": "string"
                },
                "type": "array"
              }
            },
            "multipart/form-data": {
              "schema": {
                "items": {
                  "type": "string"
                },
                "type": "array"
              }
            }
          },
          "description": "The IDs of the fields to set as columns. In the form data, specify each field as `columns=id`, where `id` is the *id* of a field (as seen in the response for [Get fields](#api-rest-api-<ver>-field-get)). For example, `columns=summary`."
        },

I wonder how we should know that this formData array has a key of columns (see description in spec) the spec doesnt really provide that information to us from what I can see.

m-rieke commented 6 months ago

I am not sure if this is changing anything, but I read the following in the Spec:

"requestBody": {
                    "content": {
                        "multipart/form-data": {
                            "schema": {
                                "items": {
                                    "$ref": "#/components/schemas/MultipartFile"
                                },
                                "type": "array"
                            }
                        }
                    },
                    "required": true
                },

and MultipartFile is defined as follows:

"MultipartFile": {
                "additionalProperties": false,
                "properties": {
                    "bytes": {
                        "items": {
                            "format": "byte",
                            "type": "string"
                        },
                        "type": "array"
                    },
                    "contentType": {
                        "type": "string"
                    },
                    "empty": {
                        "type": "boolean"
                    },
                    "inputStream": {
                        "type": "object"
                    },
                    "name": {
                        "type": "string"
                    },
                    "originalFilename": {
                        "type": "string"
                    },
                    "resource": {
                        "$ref": "#/components/schemas/Resource"
                    },
                    "size": {
                        "format": "int64",
                        "type": "integer"
                    }
                },
                "type": "object"
            }
jordanshatford commented 6 months ago

@m-rieke thanks for providing that. I will need to see what other code generators do. That still doesn't seem like a proper definition because it doesn't provide the key to use for the form data array.

jegork commented 6 months ago

I am experiencing a similar problem.

Here is the generated code:

    public static uploadFile(data: $OpenApiTs['/file/upload']['post']['req']): CancelablePromise<$OpenApiTs['/file/upload']['post']['res'][200]> {
        return __request(OpenAPI, {
            method: 'POST',
            url: '/file/upload',
            query: {
                table_name: data.tableName
            },
            formData: data.formData,
            mediaType: 'multipart/form-data',
            errors: {
                400: 'Bad Request',
                422: 'Validation Error',
                500: 'Internal Server Error'
            }
        });
    }

Error:

src/client/services.gen.ts:726:13 - error TS2322: Type 'BodyUploadFileFileUploadPost' is not assignable to type 'Record<string, unknown>'.
  Index signature for type 'string' is missing in type 'BodyUploadFileFileUploadPost'.

726             formData: data.formData,
                ~~~~~~~~

  src/client/core/ApiRequestOptions.ts:8:11
    8  readonly formData?: Record<string, unknown>;
                ~~~~~~~~
    The expected type comes from property 'formData' which is declared here on type 'ApiRequestOptions'

Found 1 error in src/client/services.gen.ts:726

OpenAPI

                "requestBody": {
                    "required": true,
                    "content": {
                        "multipart/form-data": {
                            "schema": {
                                "$ref": "#/components/schemas/Body_upload_file_file_upload_post"
                            }
                        }
                    }
                },
            "Body_upload_file_file_upload_post": {
                "properties": {
                    "file": {
                        "type": "string",
                        "format": "binary",
                        "title": "File"
                    }
                },
                "type": "object",
                "required": [
                    "file"
                ],
                "title": "Body_upload_file_file_upload_post"
            },
trevorpfiz commented 5 months ago

@jegork I am getting this as well using the fetch client. I have a FastAPI like this async def zip(file: UploadFile = File(...)):.

Type 'Body_upload_zip' is not assignable to type 'Record<string, unknown>'.
  Index signature for type 'string' is missing in type 'Body_upload_zip'.ts(2322)
ApiRequestOptions.ts(15, 12): The expected type comes from property 'formData' which is declared here on type 'ApiRequestOptions'
export type Body_upload_zip = {
    file: (Blob | File);
};

export type UploadZipData = {
    formData: Body_upload_zip;
};