openapistack / openapi-client-axios

JavaScript client library for consuming OpenAPI-enabled APIs with axios
https://openapistack.co
MIT License
558 stars 67 forks source link

typegen - how to actually use generated OpenAPI type definitions ? #65

Closed kennymalac closed 2 years ago

kennymalac commented 3 years ago

There is documentation on calling the actual client methods, but there doesn't seem to be any reference how to deal with the result of the client's response as the actual response type, nor how to import and use these types. The entire purpose of generating these OpenAPI types for me is to actually be able to use these types throughout my code, not just have a typed client with typed methods?

Please provide documentation on how to use said type definitions and actually handle the response code. There seems to be no way to import or use any of the response types.

Given the (slightly revised for example) code below:

import { Client as ApiClient } from '@/types/apiTypes'
const api = new OpenAPIClientAxios({ definition: 'http://localhost:8342/openapi.json' })

export async function apiClient() {
  return await api.getClient<ApiClient>()
}

const client = await apiClient()

const result = await client.readReport({ report_type: 'blah', report_id: 'test' })

if (typeof result.data === Components.Schemas.ReportOut) {
    console.log(result.data.details)
    console.log(result.data)
}
ERROR in utils/api.ts:19:23
TS2304: Cannot find name 'Components'.

ERROR in utils/api.ts:20:64
TS2339: Property 'details' does not exist on type 'ReportOut | HTTPValidationError'.
  Property 'details' does not exist on type 'HTTPValidationError'.

How will I be able to type check that report.data is a ReportOut type when it is in a nested namespace I cannot refer to? HTTPValidationError is returned if the response is not successful FYI. I could use "as any" but then I lose any type safety with result.data. I want to be able to use the API's ReportOut type throughout my code.

mat813 commented 3 years ago

You can't use typeof, as typescript types are only there at compile time and not at runtime. What you can do is this:

if ('details' in result.data) { // got Components.Schemas.ReportOut
    console.log(result.data.details)
    console.log(result.data)
}
kennymalac commented 3 years ago

Understood, that was my mistake, but the solution presented is quite arbitrary... What I would like is to be able use these types and accept them in function arguments:

function foo(data: ReportOut) {
  console.log(data.details)
}

And also use type guards: https://www.typescriptlang.org/docs/handbook/advanced-types.html

Can we have a way for the types to be exported?

TomFrost commented 3 years ago

In most cases I've encountered, this would be solved by #72. If I omit the error responses from my specs, there's no union type and therefore no need to check for the keys I already know are there.

npdev453 commented 2 years ago

@kennymalac You can use types from responses like this:

import { Client } from './pet.types'
type DogType = Awaited<ReturnType<Client['getPetById']>>['data']

or from requests:

type GetPetsQueryParams = Parameters<Client['getPets']>['0']
type GetPetsBodyParams = Parameters<Client['getPets']>['1']

And other way:

import { Paths} from './petshop.d.ts'

type PetsPutResolveType = Paths.PetsPut.Responses.$200
type PetsPutRejectionType = Paths.PetsPut.Responses.$500 | Paths.PetsPut.Responses.$403