@@ -1031,7 +1031,7 @@ function _generateOperationJSDoc(operationId: string, method: string, apiPath: s
10311031 return lines . join ( '\n' )
10321032}
10331033
1034- function generateApiClientContent ( operationMap : Record < string , OperationInfo > ) : string {
1034+ function generateApiClientContent ( operationMap : Record < string , OperationInfo > , useQuerySafeResponse = true ) : string {
10351035 const ids = Object . keys ( operationMap ) . sort ( )
10361036 const QUERY_HTTP = new Set ( [ 'GET' , 'HEAD' , 'OPTIONS' ] )
10371037 const isQuery = ( id : string ) => QUERY_HTTP . has ( operationMap [ id ] . method )
@@ -1040,6 +1040,9 @@ function generateApiClientContent(operationMap: Record<string, OperationInfo>):
10401040 // Registry for invalidateOperations support
10411041 const registryEntries = ids . map ( ( id ) => ` ${ id } : { path: '${ operationMap [ id ] . path } ' },` ) . join ( '\n' )
10421042
1043+ // Response type to use for queries
1044+ const queryResponseType = useQuerySafeResponse ? 'ApiResponseSafe' : 'ApiResponse'
1045+
10431046 // Generic factory helpers (4 patterns)
10441047 const helpers = `/**
10451048 * Generic query helper for operations without path parameters.
@@ -1050,7 +1053,7 @@ function _queryNoParams<Op extends AllOps>(
10501053 cfg: { path: string; method: HttpMethod; listPath: string | null },
10511054 enums: Record<string, unknown>,
10521055) {
1053- type Response = ApiResponse <Op>
1056+ type Response = ${ queryResponseType } <Op>
10541057 type QueryParams = ApiQueryParams<Op>
10551058
10561059 const useQuery = (
@@ -1117,7 +1120,7 @@ function _queryWithParams<Op extends AllOps>(
11171120) {
11181121 type PathParams = ApiPathParams<Op>
11191122 type PathParamsInput = ApiPathParamsInput<Op>
1120- type Response = ApiResponse <Op>
1123+ type Response = ${ queryResponseType } <Op>
11211124 type QueryParams = ApiQueryParams<Op>
11221125
11231126 // Two-overload interface: non-function (exact via object-literal checking) +
@@ -1392,7 +1395,7 @@ import {
13921395import type { QueryClient } from '@tanstack/vue-query'
13931396
13941397import type {
1395- ApiResponse,
1398+ ApiResponse${ useQuerySafeResponse ? ',\n ApiResponseSafe' : '' } ,
13961399 ApiRequest,
13971400 ApiPathParams,
13981401 ApiPathParamsInput,
@@ -1481,9 +1484,10 @@ async function generateApiClientFile(
14811484 openApiSpec : OpenAPISpec ,
14821485 outputDir : string ,
14831486 excludePrefix : string | null ,
1487+ useQuerySafeResponse = true ,
14841488) : Promise < void > {
14851489 const operationMap = buildOperationMap ( openApiSpec , excludePrefix )
1486- const content = generateApiClientContent ( operationMap )
1490+ const content = generateApiClientContent ( operationMap , useQuerySafeResponse )
14871491 fs . writeFileSync ( path . join ( outputDir , 'api-client.ts' ) , content )
14881492 console . log ( `✅ Generated api-client.ts (${ Object . keys ( operationMap ) . length } operations)` )
14891493}
@@ -1502,10 +1506,10 @@ Options:
15021506 --exclude-prefix PREFIX Exclude operations with operationId starting with PREFIX
15031507 (default: '_deprecated')
15041508 --no-exclude Disable operation exclusion (include all operations)
1505- --use-query-safe-response Use ApiResponseSafe for GET operations by default
1506- (default: true; query responses have only readonly fields required)
1507- --no-use-query-safe-response Disable safe response typing for GET operations
1508- (all fields required, matching ApiResponse behavior )
1509+ --use-query-safe-response Use ApiResponseSafe as return type for useQuery
1510+ (default: true; readonly fields automatically required)
1511+ --no-use-query-safe-response Use regular ApiResponse for useQuery
1512+ (readonly fields remain optional )
15091513 --help, -h Show this help message
15101514
15111515Examples:
@@ -1524,13 +1528,14 @@ This command will generate:
15241528 - api-schemas.ts (Type aliases for schema objects from OpenAPI spec)
15251529
15261530Query Response Typing (--use-query-safe-response):
1527- GET responses with this flag enabled use ApiResponseSafe, which requires only readonly
1528- fields (typically those provided by the server). This matches the semantic distinction:
1531+ When enabled (default), useQuery returns ApiResponseSafe for GET operations, which
1532+ requires only readonly fields (those the server always provides). This matches the
1533+ semantic distinction:
15291534 - POST/PATCH request bodies: optional fields (you don't have to provide everything)
15301535 - GET response bodies: readonly fields are always present (server always returns them)
15311536
1532- Disable this flag to require all fields ( ApiResponse) if your API schema doesn't
1533- properly distinguish readonly fields.
1537+ When disabled, useQuery returns ApiResponse, where readonly fields remain optional.
1538+ Use this if your API schema doesn't properly distinguish readonly fields.
15341539` )
15351540}
15361541
@@ -1843,7 +1848,6 @@ async function generateApiOperationsFile(
18431848function generateApiTypesContent (
18441849 operationMap : Record < string , OperationInfo > ,
18451850 opEnums : Record < string , Record < string , Record < string , string > > > ,
1846- useQuerySafeResponse = true ,
18471851) : string {
18481852 const ids = Object . keys ( operationMap ) . sort ( )
18491853 const isQuery = ( id : string ) => [ 'GET' , 'HEAD' , 'OPTIONS' ] . includes ( operationMap [ id ] . method )
@@ -1868,19 +1872,6 @@ function generateApiTypesContent(
18681872 ` export type Response = _ApiResponse<OpenApiOperations, '${ id } '>` ,
18691873 ]
18701874
1871- // For GET operations with useQuerySafeResponse enabled, use SafeResponse as the primary type
1872- if ( query && useQuerySafeResponse ) {
1873- commonLines . push (
1874- ` /** Response type - only \`readonly\` fields required. Recommended for GET operations. */` ,
1875- ` export type SafeResponse = _ApiResponseSafe<OpenApiOperations, '${ id } '>` ,
1876- )
1877- } else {
1878- commonLines . push (
1879- ` /** Response type - only \`readonly\` fields required. */` ,
1880- ` export type SafeResponse = _ApiResponseSafe<OpenApiOperations, '${ id } '>` ,
1881- )
1882- }
1883-
18841875 if ( ! query ) {
18851876 commonLines . push (
18861877 ` /** Request body type. */` ,
@@ -1938,12 +1929,11 @@ async function generateApiTypesFile(
19381929 openApiSpec : OpenAPISpec ,
19391930 outputDir : string ,
19401931 excludePrefix : string | null ,
1941- useQuerySafeResponse = true ,
19421932) : Promise < void > {
19431933 console . log ( '🔨 Generating api-types.ts...' )
19441934 const operationMap = buildOperationMap ( openApiSpec , excludePrefix )
19451935 const opEnums = buildOperationEnums ( openApiSpec , operationMap )
1946- const content = generateApiTypesContent ( operationMap , opEnums , useQuerySafeResponse )
1936+ const content = generateApiTypesContent ( operationMap , opEnums )
19471937 fs . writeFileSync ( path . join ( outputDir , 'api-types.ts' ) , content )
19481938 console . log ( `✅ Generated api-types.ts` )
19491939}
@@ -2003,9 +1993,9 @@ async function main(): Promise<void> {
20031993
20041994 // Log query safe response setting
20051995 if ( useQuerySafeResponse ) {
2006- console . log ( `✅ Using ApiResponseSafe for GET operations (readonly fields only required)` )
1996+ console . log ( `✅ useQuery returns ApiResponseSafe (readonly fields automatically required)` )
20071997 } else {
2008- console . log ( `⚠️ Using ApiResponse for all operations (all fields required )` )
1998+ console . log ( `ℹ️ useQuery returns ApiResponse (readonly fields remain optional )` )
20091999 }
20102000
20112001 // Fetch and parse OpenAPI spec once
@@ -2025,8 +2015,8 @@ async function main(): Promise<void> {
20252015 generateApiEnums ( openapiContent , outputDir , excludePrefix ) ,
20262016 generateApiSchemas ( openapiContent , outputDir , excludePrefix ) ,
20272017 generateApiOperationsFile ( openApiSpec , outputDir , excludePrefix , schemaEnumNames ) ,
2028- generateApiTypesFile ( openApiSpec , outputDir , excludePrefix , useQuerySafeResponse ) ,
2029- generateApiClientFile ( openApiSpec , outputDir , excludePrefix ) ,
2018+ generateApiTypesFile ( openApiSpec , outputDir , excludePrefix ) ,
2019+ generateApiClientFile ( openApiSpec , outputDir , excludePrefix , useQuerySafeResponse ) ,
20302020 ] )
20312021
20322022 console . log ( '🎉 Code generation completed successfully!' )
0 commit comments