enkot / nuxt-open-fetch

Generate zero-overhead, typed OpenAPI clients for Nuxt.
https://nuxt-open-fetch.vercel.app
MIT License
114 stars 10 forks source link

Expose request and response types in a simple way #31

Open huang-julien opened 3 months ago

huang-julien commented 3 months ago

Hey thanks for your module !

I'm coming from open-api-generator with axios-typescript which exposes enum and types directly from what's generated.

It could be nice to expose directly quer/params and response types from generation and maybe adding them to auto-import ?

Currently the only way to retrieve thse types is to import from the operations type:

import type { operations } from "#build/types/nuxt-open-fetch/schemas/---.ts"

function parms (param: operations['...']['query']) {}
enkot commented 3 months ago

Hi @huang-julien, I like the idea. There is a PR in openapi-typescript to solve this problem https://github.com/drwpow/openapi-typescript/pull/1260.

Unfortunately, the author said he won't be working on it anymore, so I'll give it a shot :)

The main problem as I understand is this one:

the proposal to have top-level “friendly names” doesn’t work for many schemas, because you’re allowed to use characters in component names that aren’t JS-safe. So we’d have to rename them somehow, while preventing conflicts.

huang-julien commented 3 months ago

interesting :eyes: ... I'll be waiting then. i'm just doing a workaround ATM:

import type { operations } from '#build/types/nuxt-open-fetch/schemas/bff'

export type OperationParameters<T extends keyof operations> = 'parameters' extends keyof operations[T]
    ? operations[T]['parameters']
    : never

// example
function (t: Partial<OperationParameters<'GetPet'>['query']>) {
    $fetch('...', { query : t })
}

It does work but def not my fav way of using types haha

I don't have a solution for enums yet. For now enums generated from open-api-generator with axios-typescript are compatible with openapi-typescript

enkot commented 3 months ago

Created a PR to export types with friendly names https://github.com/drwpow/openapi-typescript/pull/1599. But it's an open question which level of nested types for paths should be aliased and what is the most convenient way to use them:

RequestEnterpriseAdminListGlobalWebhooks['query']
// or
RequestEnterpriseAdminListGlobalWebhooksQuery
// or
EnterpriseAdminListGlobalWebhooksQuery
// etc

Good news is that enums generation is supported out of the box in v7 by using --enum flag :)

jonkri commented 1 week ago

I'm not sure if it's relevant for this issue. 😅 I'm wondering how I can access the response type for a certain request.

I would like to type my Pinia store without having to type something like this:

export const useStore = defineStore("test", {
  // ...
  state: () => ({
    token: null as null | string,
    userInfo: null as {
      deactivate?: string | undefined;
      email: string;
      id: string;
      instances: {
        id: string;
        name: string;
      }[];
      name: string;
      phone?: string | undefined;
      roles: string[];
    } | null
  })
});

Ideally the code would look something like this:

export const useStore = defineStore("test", {
  // ...
  state: () => ({
    token: null as null | string,
    userInfo: null as UserInfoByToken | null
  })
});

Here's the code I'm using to set userInfo:

const { data, error } = await useAuthService(
  "/user-info-by-token/{token}",
  {
    path: { token: this.token }
  }
);

this.userInfo = data.value;
jd-solanki commented 1 week ago

@jonkri I suggest opening new issue for this. However, here's my suggestion as per what I understand you're trying to do:

  1. You can import the type and assign it

    import type { operations } from '#build/types/open-fetch/schemas/api'
    
    export const useStore = defineStore("test", {
      // ...
      state: () => ({
        token: null as null | string,
    
        // You can get type from operations. You've to update below type according to your API
        userInfo: null as operations['...']['...'] | null,
      })
    });
  2. Additionally, I've also created few type utils for myself. These are custom made so there can be chances of improving it. I'm using it for my personal use and they're fine till now. This might look confusing so if you are beginner avoid this.

    import type { operations } from '#build/types/open-fetch/schemas/api'
    
    export type ApiResponse<T extends keyof operations, R extends keyof operations[T]['responses']> = operations[T]['responses'][R] extends { content: { 'application/json': infer U } }
      ? U
      : never
    
    export type ApiRequestBody<T extends keyof operations> = operations[T]['requestBody'] extends { content: { 'application/json': infer U } }
      ? U
      : never
    
    export type ApiRequestQueryParams<T extends keyof operations> = operations[T]['parameters'] extends { query?: infer U } ? U : never

    Here's how you can use it:

    import type { operations } from '#build/types/open-fetch/schemas/api'
    
    export const useStore = defineStore("test", {
      // ...
      state: () => ({
        token: null as null | string,
    
        // You can get type from operations. You've to update below type according to your API
        userInfo: null as ApiResponse<'get_users__user_id', 200>,
      })
    });