1- import { initClient , ApiFetcherArgs } from '@ts-rest/core' ;
1+ import { initClient } from '@ts-rest/core' ;
22import axios , { AxiosError } from 'axios' ;
33import { tadataContract } from './tadata-contract' ;
44import { AuthError , NetworkError , ApiError } from '../errors' ;
55import { Logger } from '../core/logger' ;
66
77interface ClientOptions {
8- baseUrl ? : string ;
9- version ? : string ;
8+ baseUrl : string ;
9+ version : string ;
1010 timeout ?: number ;
1111 logger ?: Logger ;
12+ isDev : boolean ;
13+ }
14+
15+ // Custom type for the fetcher args that includes query
16+ interface CustomApiFetcherArgs {
17+ path : string ;
18+ method : string ;
19+ body ?: any ;
20+ headers : Record < string , string > ;
21+ query ?: Record < string , string > ;
1222}
1323
1424/**
1525 * Creates a configured ts-rest client for the Tadata API
1626 */
17- export function createApiClient ( apiKey : string , options : ClientOptions = { } ) {
18- const {
19- baseUrl = 'https://api.tadata.com' ,
20- version = 'latest' ,
21- timeout = 30000 ,
22- logger,
23- } = options ;
27+ export function createApiClient ( apiKey : string , options : ClientOptions ) {
28+ const { baseUrl, version, timeout = 30000 , logger } = options ;
2429
2530 // Create axios instance with defaults
2631 const axiosInstance = axios . create ( {
2732 baseURL : baseUrl ,
2833 timeout,
2934 headers : {
3035 'Authorization' : `Bearer ${ apiKey } ` ,
31- 'x-tadata -version' : version ,
36+ 'x-api -version' : version ,
3237 'Content-Type' : 'application/json' ,
3338 } ,
3439 } ) ;
@@ -41,7 +46,12 @@ export function createApiClient(apiKey: string, options: ClientOptions = {}) {
4146 return config ;
4247 } ,
4348 error => {
44- logger . error ( 'Request error:' , error ) ;
49+ // Format error for cleaner logs
50+ const errorInfo = {
51+ message : error . message ,
52+ code : error . code
53+ } ;
54+ logger . error ( 'Request error' , errorInfo ) ;
4555 return Promise . reject ( error ) ;
4656 }
4757 ) ;
@@ -52,7 +62,29 @@ export function createApiClient(apiKey: string, options: ClientOptions = {}) {
5262 return response ;
5363 } ,
5464 error => {
55- logger . error ( 'Response error:' , error ) ;
65+ // Format error for cleaner logs
66+ let errorInfo : Record < string , any > = {
67+ message : error . message ,
68+ code : error . code
69+ } ;
70+
71+ if ( error . response ) {
72+ errorInfo . status = error . response . status ;
73+
74+ // Extract specific error details
75+ if ( error . response . data && error . response . data . error ) {
76+ errorInfo . errorCode = error . response . data . error . code ;
77+ errorInfo . errorMessage = error . response . data . error . message ;
78+
79+ // Include first validation error if present
80+ if ( error . response . data . error . errors &&
81+ error . response . data . error . errors . length > 0 ) {
82+ errorInfo . validation = error . response . data . error . errors [ 0 ] ;
83+ }
84+ }
85+ }
86+
87+ logger . error ( 'Response error' , errorInfo ) ;
5688 return Promise . reject ( error ) ;
5789 }
5890 ) ;
@@ -63,23 +95,33 @@ export function createApiClient(apiKey: string, options: ClientOptions = {}) {
6395 baseUrl,
6496 baseHeaders : {
6597 'Authorization' : `Bearer ${ apiKey } ` ,
66- 'x-tadata -version' : version ,
98+ 'x-api -version' : version ,
6799 } ,
68- /* <<<<<<<<<<<<<< ✨ Windsurf Command ⭐ >>>>>>>>>>>>>>>> */
100+
69101 /**
70102 * Adapter for `ts-rest` to perform API requests to the Tadata API.
71103 *
72- * @param {ApiFetcherArgs<any> } args - Request arguments with path, method, body, and headers .
104+ * @param {CustomApiFetcherArgs } args - Request arguments with path, method, body, headers, and query params .
73105 * @returns {Promise<ApiResponse<any>> } - Response with status, body, and headers.
74106 * @throws {AuthError } - If authentication fails.
75107 * @throws {ApiError } - If the API returns an error response.
76108 * @throws {NetworkError } - If a network error occurs.
77109 */
78- /* <<<<<<<<<< 5f3418b3-bf5f-4f26-b9b9-206215461c08 >>>>>>>>>>> */
79- api : async ( { path, method, body, headers } : ApiFetcherArgs < any > ) => {
110+ api : async ( { path, method, body, headers, query = { } } : CustomApiFetcherArgs ) => {
80111 try {
112+ // Add the apiKey to query parameters for every request
113+ // This avoids having to manually add it in each method call
114+ const augmentedQuery = {
115+ ...query ,
116+ apiKey,
117+ } ;
118+
119+ // Create query string
120+ const queryString = new URLSearchParams ( augmentedQuery ) . toString ( ) ;
121+ const urlWithQuery = queryString ? `${ path } ?${ queryString } ` : path ;
122+
81123 const config : any = {
82- url : path ,
124+ url : urlWithQuery ,
83125 method,
84126 headers,
85127 } ;
@@ -105,7 +147,8 @@ export function createApiClient(apiKey: string, options: ClientOptions = {}) {
105147 }
106148
107149 const { status, data } = axiosError . response ;
108- const errorMessage = typeof data === 'object' && data !== null ? ( data as any ) . message : undefined ;
150+ const errorMessage =
151+ typeof data === 'object' && data !== null ? ( data as any ) . message : undefined ;
109152
110153 if ( status === 401 || status === 403 ) {
111154 throw new AuthError ( errorMessage || 'Authentication failed' , axiosError ) ;
0 commit comments