orval-labs / orval

orval is able to generate client with appropriate type-signatures (TypeScript) from any valid OpenAPI v3 or Swagger v2 specification, either in yaml or json formats. 🍺
https://orval.dev
MIT License
3.18k stars 336 forks source link

Vue Query: generates code that doesn't compile for vue-query #1467

Open pbrzosko opened 5 months ago

pbrzosko commented 5 months ago

What are the steps to reproduce this issue?

  1. Having this swagger "requestBody": { "content": { "multipart/form-data": { "schema": { "type": "object", "properties": { "formFile": { "type": "string", "format": "binary", "nullable": true } } } } } },
  2. Execute orval with vue-query

What happens?

Orval generates code, that doesn't compile:

export const protocolImport = (
    protocolImportBody: MaybeRef<ProtocolImportBody>, options?: AxiosRequestConfig
 ): Promise<AxiosResponse<ImportProtocolsResponse>> => {const formData = new FormData();
if(protocolImportBody.formFile !== undefined && protocolImportBody.formFile !== null) {
 formData.append('formFile', protocolImportBody.formFile)
 }

    protocolImportBody = unref(protocolImportBody);
    return axios.post(
      `/protocol/import`,
      formData,options
    );
  }

What were you expecting to happen?

Code compiles.

Any logs, error output, etc?

error TS2339: Property 'formFile' does not exist on type 'MaybeRef'. Property 'formFile' does not exist on type 'Ref'.

846 if(protocolImportBody.formFile !== undefined && protocolImportBody.formFile !== null) {


error TS2339: Property 'formFile' does not exist on type 'MaybeRef<ProtocolImportBody>'.
  Property 'formFile' does not exist on type 'Ref<ProtocolImportBody>'.

846 if(protocolImportBody.formFile !== undefined && protocolImportBody.formFile !== null) {

error TS2339: Property 'formFile' does not exist on type 'MaybeRef'. Property 'formFile' does not exist on type 'Ref'.

847 formData.append('formFile', protocolImportBody.formFile)

Any other comments?

I guess the issue is that body is unwrapped after appending file to it. Do you have some workaround so that I can have a code that compiles?

What versions are you using?

Operating System: OSX Sonoma 14.5 Package Version: 6.30.2 Browser Version: Version 126.0.6478.57 (Official Build) (arm64)

john-nhoj commented 4 months ago

@pbrzosko , have you found a workaround? I find myself in a similar situation and found out it is because the variable is not wrapped with unref

pbrzosko commented 4 months ago

Yeah, for now I have overwritten the formBody, If I remember correctly, to be empty just for this one endpoint I have with an error. I don't use this endpoint for now so I could do it like that.

john-nhoj commented 4 months ago

Ok, I found a workaround.

If you use a custom instance of Axios, the generated client uses unref correctly.

You can copy this file from samples/vue-query: https://github.com/anymaniax/orval/blob/833faeb9cc656a2ec87816479a4ebf9321edfc89/samples/vue-query/src/api/mutator/custom-instance.ts

And if you re-run the generation, for me, it fixed those variables accessed before unref is called. Hope it helps!

pbrzosko commented 3 months ago

Another example:

const queryFn: QueryFunction<Awaited<ReturnType<typeof sampleEntityGetMetadata>>> = ({ signal }) => sampleEntityGetMetadata(unref(id,params), { signal, ...fetchOptions });

There are two errors here:

Seems like it should simply be:

const queryFn: QueryFunction<Awaited<ReturnType<typeof sampleEntityGetMetadata>>> = ({ signal }) => sampleEntityGetMetadata(unref(id), unref(params), { signal, ...fetchOptions });
Maxim-Mazurok commented 4 days ago

Hey guys, this seems to be an edge-case for when using formData

Correct code generated should probably be something like this:

if(unref(protocolImportBody).formFile !== undefined && protocolImportBody.formFile !== null) {
 formData.append('formFile', unref(protocolImportBody).formFile)
 }

This is because protocolImportBody is of MaybeRef<...> type, so it has to be un-refed

I probably won't have capacity to create a PR to fix this, but someone could search where we're adding unref and handle the formData edge case. Cheers!

MadManMcIvor commented 2 days ago

When you have a GET method with both a path and query params it causes the unref(id,params) instead of unref(id), unref(params),... issue as well.

Seems to work fine if it's all query params, or just a path param, but mixing the two produces that error.

Maxim-Mazurok commented 2 days ago

@MadManMcIvor this is probably a regression, I just checked v6.22.1 that we're using and it produces correct code for such case where you have both path and query parameters for get request:

export const getApiV1LibraryAuTariffconcessionsInstrumentNo = (
  instrumentNo: MaybeRef<string | undefined | null>,
  params?: MaybeRef<GetApiV1LibraryAuTariffconcessionsInstrumentNoParams>,
  options?: AxiosRequestConfig,
): Promise<AxiosResponse<TariffConcession[]>> => {
  instrumentNo = unref(instrumentNo);
  params = unref(params);
  return axios.default.get(`/api/v1/library/au/tariffconcessions/${encodeURIComponent(String(instrumentNo))}`, {
    ...options,
    params: { ...unref(params), ...options?.params },
  });
};
"/api/v1/library/au/tariffconcessions/{instrumentNo}": {
      "get": {
        "tags": [
          "V1AULibrary"
        ],
        "parameters": [
          {
            "name": "instrumentNo",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "year",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "2017"
            }
          }
        ],

Probably best to create a new issue for this tho, cheers!

MadManMcIvor commented 2 days ago

Will do. Thanks, @Maxim-Mazurok!