ts-typed-api 0.2.15 → 0.2.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -128,6 +128,18 @@ export declare class ApiClient<TActualDef extends BaseApiDefinitionSchema> {
128
128
  * @returns The base URL with prefix applied.
129
129
  */
130
130
  private getBaseUrlWithPrefix;
131
+ /**
132
+ * Generates the full URL for a specific route, incorporating path parameters and query parameters.
133
+ * @template TDomain The domain (controller) of the API.
134
+ * @template TRouteKey The key of the route within the domain.
135
+ * @param domain The API domain (e.g., 'user').
136
+ * @param routeKey The API route key (e.g., 'getUsers').
137
+ * @param params Optional path parameters to replace in the route path.
138
+ * @param query Optional query parameters to append to the URL.
139
+ * @returns The full URL as a string.
140
+ * @throws Error if the route configuration is invalid.
141
+ */
142
+ generateUrl<TDomain extends keyof TActualDef['endpoints'], TRouteKey extends keyof TActualDef['endpoints'][TDomain]>(domain: TDomain, routeKey: TRouteKey, params?: ApiClientParams<TActualDef, TDomain, TRouteKey>, query?: ApiClientQuery<TActualDef, TDomain, TRouteKey>): string;
131
143
  /**
132
144
  * Makes an API call to a specified domain and route.
133
145
  * @template TDomain The domain (controller) of the API.
package/dist/client.js CHANGED
@@ -88,6 +88,42 @@ class ApiClient {
88
88
  }
89
89
  return this.baseUrl;
90
90
  }
91
+ /**
92
+ * Generates the full URL for a specific route, incorporating path parameters and query parameters.
93
+ * @template TDomain The domain (controller) of the API.
94
+ * @template TRouteKey The key of the route within the domain.
95
+ * @param domain The API domain (e.g., 'user').
96
+ * @param routeKey The API route key (e.g., 'getUsers').
97
+ * @param params Optional path parameters to replace in the route path.
98
+ * @param query Optional query parameters to append to the URL.
99
+ * @returns The full URL as a string.
100
+ * @throws Error if the route configuration is invalid.
101
+ */
102
+ generateUrl(domain, routeKey, params, query) {
103
+ const routeInfo = this.apiDefinitionObject.endpoints[domain][routeKey];
104
+ if (!routeInfo || typeof routeInfo.path !== 'string') {
105
+ throw new Error(`API route configuration ${String(domain)}.${String(routeKey)} not found or invalid.`);
106
+ }
107
+ let urlPath = routeInfo.path;
108
+ if (params) {
109
+ const paramsRecord = params;
110
+ for (const key in paramsRecord) {
111
+ if (Object.prototype.hasOwnProperty.call(paramsRecord, key) && paramsRecord[key] !== undefined) {
112
+ urlPath = urlPath.replace(`:${key}`, String(paramsRecord[key]));
113
+ }
114
+ }
115
+ }
116
+ const url = new URL(this.getBaseUrlWithPrefix() + urlPath);
117
+ if (query) {
118
+ const queryRecord = query;
119
+ for (const key in queryRecord) {
120
+ if (Object.prototype.hasOwnProperty.call(queryRecord, key) && queryRecord[key] !== undefined) {
121
+ url.searchParams.append(key, String(queryRecord[key]));
122
+ }
123
+ }
124
+ }
125
+ return url.toString();
126
+ }
91
127
  /**
92
128
  * Makes an API call to a specified domain and route.
93
129
  * @template TDomain The domain (controller) of the API.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-typed-api",
3
- "version": "0.2.15",
3
+ "version": "0.2.16",
4
4
  "description": "A lightweight, type-safe RPC library for TypeScript with Zod validation",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/client.ts CHANGED
@@ -216,6 +216,56 @@ export class ApiClient<TActualDef extends BaseApiDefinitionSchema> { // Made gen
216
216
  return this.baseUrl;
217
217
  }
218
218
 
219
+ /**
220
+ * Generates the full URL for a specific route, incorporating path parameters and query parameters.
221
+ * @template TDomain The domain (controller) of the API.
222
+ * @template TRouteKey The key of the route within the domain.
223
+ * @param domain The API domain (e.g., 'user').
224
+ * @param routeKey The API route key (e.g., 'getUsers').
225
+ * @param params Optional path parameters to replace in the route path.
226
+ * @param query Optional query parameters to append to the URL.
227
+ * @returns The full URL as a string.
228
+ * @throws Error if the route configuration is invalid.
229
+ */
230
+ public generateUrl<
231
+ TDomain extends keyof TActualDef['endpoints'],
232
+ TRouteKey extends keyof TActualDef['endpoints'][TDomain]
233
+ >(
234
+ domain: TDomain,
235
+ routeKey: TRouteKey,
236
+ params?: ApiClientParams<TActualDef, TDomain, TRouteKey>,
237
+ query?: ApiClientQuery<TActualDef, TDomain, TRouteKey>
238
+ ): string {
239
+ const routeInfo = this.apiDefinitionObject.endpoints[domain as string][routeKey as string] as RouteSchema;
240
+
241
+ if (!routeInfo || typeof routeInfo.path !== 'string') {
242
+ throw new Error(`API route configuration ${String(domain)}.${String(routeKey)} not found or invalid.`);
243
+ }
244
+
245
+ let urlPath = routeInfo.path;
246
+ if (params) {
247
+ const paramsRecord = params as Record<string, string | number | boolean>;
248
+ for (const key in paramsRecord) {
249
+ if (Object.prototype.hasOwnProperty.call(paramsRecord, key) && paramsRecord[key] !== undefined) {
250
+ urlPath = urlPath.replace(`:${key}`, String(paramsRecord[key]));
251
+ }
252
+ }
253
+ }
254
+
255
+ const url = new URL(this.getBaseUrlWithPrefix() + urlPath);
256
+
257
+ if (query) {
258
+ const queryRecord = query as Record<string, any>;
259
+ for (const key in queryRecord) {
260
+ if (Object.prototype.hasOwnProperty.call(queryRecord, key) && queryRecord[key] !== undefined) {
261
+ url.searchParams.append(key, String(queryRecord[key]));
262
+ }
263
+ }
264
+ }
265
+
266
+ return url.toString();
267
+ }
268
+
219
269
  /**
220
270
  * Makes an API call to a specified domain and route.
221
271
  * @template TDomain The domain (controller) of the API.
@@ -107,6 +107,26 @@ describe.each([
107
107
  expect(customHeader).toBe('test-value');
108
108
  expect(anotherHeader).toBe('another-value');
109
109
  });
110
+
111
+ test('generateUrl should return correct URL for ping', () => {
112
+ const url = client.generateUrl('common', 'ping');
113
+ expect(url).toBe(`${baseUrl}/api/v1/public/ping`);
114
+ });
115
+
116
+ test('generateUrl should return correct URL for probe1 without query', () => {
117
+ const url = client.generateUrl('status', 'probe1');
118
+ expect(url).toBe(`${baseUrl}/api/v1/public/status/probe1`);
119
+ });
120
+
121
+ test('generateUrl should return correct URL for probe1 with query', () => {
122
+ const url = client.generateUrl('status', 'probe1', undefined, { match: true });
123
+ expect(url).toBe(`${baseUrl}/api/v1/public/status/probe1?match=true`);
124
+ });
125
+
126
+ test('generateUrl should return correct URL for probe2', () => {
127
+ const url = client.generateUrl('status', 'probe2');
128
+ expect(url).toBe(`${baseUrl}/api/v1/public/status/probe2`);
129
+ });
110
130
  });
111
131
 
112
132
  describe('Private API', () => {
@@ -127,6 +147,11 @@ describe.each([
127
147
 
128
148
  expect(result).toBe('ok');
129
149
  });
150
+
151
+ test('generateUrl should return correct URL for user get with params', () => {
152
+ const url = client.generateUrl('user', 'get', { id: 'test-id' });
153
+ expect(url).toBe(`${baseUrl}/api/v1/private/user/test-id`);
154
+ });
130
155
  });
131
156
 
132
157
  describe('Strict Validation Tests', () => {