Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unstable return reference of generated hook when using a custom mutator hook. #1359

Closed
henkerik opened this issue May 6, 2024 · 5 comments · Fixed by #1374
Closed

Unstable return reference of generated hook when using a custom mutator hook. #1359

henkerik opened this issue May 6, 2024 · 5 comments · Fixed by #1374
Assignees
Labels
bug Something isn't working tanstack-query TanStack Query related issue
Milestone

Comments

@henkerik
Copy link
Contributor

henkerik commented May 6, 2024

What are the steps to reproduce this issue?

First of all, thanks for building Orval. We use it for quite a few projects 👍 .

One can generate endpoints with a custom mutator hook, for example:

https://github.com/anymaniax/orval/blob/4cfb246ce5f1816a9c809f96d9d2f2c5a80eac4a/samples/react-query/hook-mutator/endpoints.ts#L36-L38

export const useListPetsHook = () => {
  const listPets = useCustomInstance<Pets>();

  return (params?: ListPetsParams, signal?: AbortSignal) => {
    return listPets({ url: `/pets`, method: 'GET', params, signal });
  };
};

What happens?

The reference returned by the generated useListPetsHook isn't stable: it changes on every render cycle.

What were you expecting to happen?

I would have expected the following:

export const useListPetsHook = () => {
  const listPets = useCustomInstance<Pets>();

  return useCallback((params?: ListPetsParams, signal?: AbortSignal) => {
    return listPets({ url: `/pets`, method: 'GET', params, signal });
  }, [listPets]);
};

Now, the useListPetsHook will return the same reference on subsequent calls (given that your useCustomInstance doesn't change of course).

A stable reference is useful when one uses memoization downstream, and the result of the useListPetsHook is part of a useMemo or useCallback call in user-land code.

@melloware melloware added bug Something isn't working tanstack-query TanStack Query related issue labels May 6, 2024
@henkerik henkerik changed the title Unstable return reference of generated hooks when using a custom mutator hook. Unstable return reference of generated hook when using a custom mutator hook. May 7, 2024
@melloware melloware added this to the 6.29.0 milestone May 14, 2024
@Selfmade-RuLeZ
Copy link

Hi guys, I think this merge broke something, as the useCallback is not imported into the generated files which are affected by a custom axios instance.

src/generated/xxx/xxx.ts106:16- error TS2304: Cannot find name 'useCallback'.

Here is my orval.config.ts:

import { defineConfig } from "orval";

export default defineConfig({
  petstore: {
    input: "./openapi/openapi.yaml",
    output: {
      mode: "tags-split",
      target: "./src/generated/api.ts",
      client: "react-query",
      override: {
        tags: {
          someTag: {
            mutator: {
              path: "./src/features/xxx/xxx/orval/useCustomInstance",
              name: "useCustomInstance",
            },
          },
        },
      },
    },
    hooks: {
      afterAllFilesWrite: "prettier --write",
    },
  },
});

If you want to, I could also add another issue, but I guess it is hardly related to this one. It is working with version 6.25.0

@melloware
Copy link
Collaborator

Hmmm I am not having that issue with 7.1.0? You can see my generated code here and it has useCallback

https://github.com/melloware/quarkus-primereact/blob/main/src/main/webui/src/service/CarService.ts

@Selfmade-RuLeZ
Copy link

I updated to 7.1.0 and the error is still there. I will try to recreate a minimal example with our usecase to provide you more information.

@Selfmade-RuLeZ
Copy link

So here is my minimal example to reproduce this. I guess it has something todo with the tag dependent instance. I need a custom instance in my project for some tags to set some headers but only for this specific request. So I don't want to use an interceptor for this one.

api.yaml:

openapi: '3.0.0'
info:
  version: 1.0.0
  title: Swagger Petstore
  license:
    name: MIT
servers:
  - url: http://petstore.swagger.io/v1
paths:
  /pets:
    get:
      summary: List all pets
      operationId: listPets
      tags:
        - pets
        - my-tag
      parameters:
        - name: limit
          in: query
          description: How many items to return at one time (max 100)
          required: false
          schema:
            type: string
      responses:
        '200':
          description: A paged array of pets
          headers:
            x-next:
              description: A link to the next page of responses
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PetsArray'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    post:
      summary: Create a pet
      operationId: createPets
      tags:
        - pets
        - my-tag
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - 'name'
                - 'tag'
              properties:
                name:
                  type: string
                tag:
                  type: string
      responses:
        '201':
          description: Null response
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /pets-nested-array:
    get:
      summary: List all pets as nested array
      operationId: listPetsNestedArray
      tags:
        - pets
      parameters:
        - name: limit
          in: query
          description: How many items to return at one time (max 100)
          required: false
          schema:
            type: string
      responses:
        '200':
          description: A paged array of pets
          headers:
            x-next:
              description: A link to the next page of responses
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PetsNestedArray'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /pets/{petId}:
    get:
      summary: Info for a specific pet
      operationId: showPetById
      tags:
        - pets
      parameters:
        - name: petId
          in: path
          required: true
          description: The id of the pet to retrieve
          schema:
            type: string
        - name: testId
          in: path
          required: true
          description: The id of the pet to retrieve
          schema:
            type: string
      responses:
        '200':
          description: Expected response to a valid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    Pet:
      type: object
      required:
        - id
        - name
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string
          description: 'Name of pet'
          maxLength: 0
          minLength: 40
        age:
          type: integer
          format: int32
          minimum: 0
          maximum: 30
          exclusiveMinimum: true
          exclusiveMaximum: true
        tag:
          type: string
          pattern: '^\\d{3}-\\d{2}-\\d{4}$'
          nullable: true
        email:
          type: string
          format: email
        callingCode:
          type: string
          enum: ['+33', '+420', '+33'] # intentional duplicated value
        country:
          type: string
          enum: ["People's Republic of China", 'Uruguay']
    PetsNestedArray:
      type: object
      required:
        - pets
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Pet'
    PetsArray:
      type: array
      minItems: 1
      maxItems: 20
      items:
        $ref: '#/components/schemas/Pet'
    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: integer
          format: int32
        message:
          type: string

orval.config.ts

import { defineConfig } from "orval";

export default defineConfig({
  petstore: {
    input: "./petstore.yaml",
    output: {
      mode: "tags-split",
      target: "./src/generated/my_api.ts",
      client: "react-query",
      override: {
        tags: {
          "my-tag": {
            mutator: {
              path: "./src/instance/useCustomInstance.ts",
              name: "useCustomInstance",
            },
          },
        },
      },
    },
  },
});

The custom instance:

import {AxiosRequestConfig, AxiosResponse} from "axios";
import axios from "axios";

export const useCustomInstance = <T>(): ((
    config: AxiosRequestConfig,
    options?: AxiosRequestConfig,
) => Promise<AxiosResponse<T>>) => {
    const someHeaders = {
        "Header-A": "someString"
    }
    return (config: AxiosRequestConfig, options?: AxiosRequestConfig) => {
        const promise = axios
            .request({
                ...config,
                headers: {
                    ...someHeaders
                },
                ...options,
            })
            .then(({data}) => data);
        return promise;
    };
};

@melloware
Copy link
Collaborator

I would open a new ticket since this is a specific use case failing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working tanstack-query TanStack Query related issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants