@webpieces/http-client 0.1.0

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/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # @webpieces/http-client
2
+
3
+ > HTTP client for WebPieces framework
4
+
5
+ Part of the [WebPieces TypeScript](https://github.com/deanhiller/webpieces-ts) framework.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @webpieces/http-client
11
+ ```
12
+
13
+ ## Documentation
14
+
15
+ See the main [WebPieces README](https://github.com/deanhiller/webpieces-ts#readme) for complete documentation and examples.
16
+
17
+ ## License
18
+
19
+ Apache-2.0
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@webpieces/http-client",
3
+ "version": "0.1.0",
4
+ "description": "HTTP client for WebPieces framework",
5
+ "type": "commonjs",
6
+ "main": "./src/index.js",
7
+ "types": "./src/index.d.ts",
8
+ "author": "Dean Hiller",
9
+ "license": "Apache-2.0",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/deanhiller/webpieces-ts.git",
13
+ "directory": "packages/http/http-client"
14
+ },
15
+ "keywords": [
16
+ "webpieces",
17
+ "http",
18
+ "client"
19
+ ],
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "dependencies": {
24
+ "@webpieces/http-api": "0.1.0"
25
+ }
26
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Configuration options for HTTP client.
3
+ */
4
+ export interface ClientConfig {
5
+ /** Base URL for all requests (e.g., 'http://localhost:3000') */
6
+ baseUrl: string;
7
+ /** Optional headers to include in all requests */
8
+ headers?: Record<string, string>;
9
+ /** Optional fetch implementation (defaults to global fetch) */
10
+ fetch?: typeof fetch;
11
+ }
12
+ /**
13
+ * Creates a type-safe HTTP client from an API interface prototype.
14
+ *
15
+ * This is the client-side equivalent of RESTApiRoutes.
16
+ * - Server: RESTApiRoutes reads decorators → routes HTTP requests to controllers
17
+ * - Client: createClient reads decorators → generates HTTP requests from method calls
18
+ *
19
+ * Usage:
20
+ * ```typescript
21
+ * const client = createClient(SaveApiPrototype, { baseUrl: 'http://localhost:3000' });
22
+ * const response = await client.save({ query: 'test' }); // Type-safe!
23
+ * ```
24
+ *
25
+ * @param apiPrototype - The API prototype class with decorators (e.g., SaveApiPrototype)
26
+ * @param config - Client configuration (baseUrl, headers, etc.)
27
+ * @returns A proxy object that implements the API interface
28
+ */
29
+ export declare function createClient<T extends object>(apiPrototype: Function & {
30
+ prototype: T;
31
+ }, config: ClientConfig): T;
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createClient = createClient;
4
+ const http_api_1 = require("@webpieces/http-api");
5
+ /**
6
+ * Creates a type-safe HTTP client from an API interface prototype.
7
+ *
8
+ * This is the client-side equivalent of RESTApiRoutes.
9
+ * - Server: RESTApiRoutes reads decorators → routes HTTP requests to controllers
10
+ * - Client: createClient reads decorators → generates HTTP requests from method calls
11
+ *
12
+ * Usage:
13
+ * ```typescript
14
+ * const client = createClient(SaveApiPrototype, { baseUrl: 'http://localhost:3000' });
15
+ * const response = await client.save({ query: 'test' }); // Type-safe!
16
+ * ```
17
+ *
18
+ * @param apiPrototype - The API prototype class with decorators (e.g., SaveApiPrototype)
19
+ * @param config - Client configuration (baseUrl, headers, etc.)
20
+ * @returns A proxy object that implements the API interface
21
+ */
22
+ function createClient(apiPrototype, config) {
23
+ // Validate that the API prototype is marked with @ApiInterface
24
+ if (!(0, http_api_1.isApiInterface)(apiPrototype)) {
25
+ const className = apiPrototype.name || 'Unknown';
26
+ throw new Error(`Class ${className} must be decorated with @ApiInterface()`);
27
+ }
28
+ // Get all routes from the API prototype
29
+ const routes = (0, http_api_1.getRoutes)(apiPrototype);
30
+ // Create a map of method name -> route metadata for fast lookup
31
+ const routeMap = new Map();
32
+ for (const route of routes) {
33
+ routeMap.set(route.methodName, route);
34
+ }
35
+ // Use fetch implementation from config or global
36
+ const fetchImpl = config.fetch || fetch;
37
+ // Create a proxy that intercepts method calls and makes HTTP requests
38
+ return new Proxy({}, {
39
+ get(target, prop) {
40
+ // Only handle string properties (method names)
41
+ if (typeof prop !== 'string') {
42
+ return undefined;
43
+ }
44
+ // Get the route metadata for this method
45
+ const route = routeMap.get(prop);
46
+ if (!route) {
47
+ throw new Error(`No route found for method ${prop}`);
48
+ }
49
+ // Return a function that makes the HTTP request
50
+ return async (...args) => {
51
+ return makeRequest(fetchImpl, config, route, args);
52
+ };
53
+ },
54
+ });
55
+ }
56
+ /**
57
+ * Make an HTTP request based on route metadata and arguments.
58
+ */
59
+ async function makeRequest(fetchImpl, config, route, args) {
60
+ const { httpMethod, path } = route;
61
+ // Build the full URL
62
+ const url = `${config.baseUrl}${path}`;
63
+ // Build headers
64
+ const headers = {
65
+ 'Content-Type': 'application/json',
66
+ ...config.headers,
67
+ };
68
+ // Build request options
69
+ const options = {
70
+ method: httpMethod,
71
+ headers,
72
+ };
73
+ // For POST/PUT/PATCH, include the body (first argument)
74
+ if (['POST', 'PUT', 'PATCH'].includes(httpMethod) && args.length > 0) {
75
+ options.body = JSON.stringify(args[0]);
76
+ }
77
+ // Make the HTTP request
78
+ const response = await fetchImpl(url, options);
79
+ // Check for HTTP errors
80
+ if (!response.ok) {
81
+ const errorText = await response.text();
82
+ throw new Error(`HTTP ${response.status}: ${response.statusText}. ${errorText}`);
83
+ }
84
+ // Parse and return the JSON response
85
+ return response.json();
86
+ }
87
+ //# sourceMappingURL=ClientFactory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ClientFactory.js","sourceRoot":"","sources":["../../../../../packages/http/http-client/src/ClientFactory.ts"],"names":[],"mappings":";;AA+BA,oCA4CC;AA3ED,kDAA+E;AAc/E;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,YAAY,CAC1B,YAAyC,EACzC,MAAoB;IAEpB,+DAA+D;IAC/D,IAAI,CAAC,IAAA,yBAAc,EAAC,YAAY,CAAC,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,IAAI,SAAS,CAAC;QACjD,MAAM,IAAI,KAAK,CACb,SAAS,SAAS,yCAAyC,CAC5D,CAAC;IACJ,CAAC;IAED,wCAAwC;IACxC,MAAM,MAAM,GAAG,IAAA,oBAAS,EAAC,YAAY,CAAC,CAAC;IAEvC,gEAAgE;IAChE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAC;IAClD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACxC,CAAC;IAED,iDAAiD;IACjD,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC;IAExC,sEAAsE;IACtE,OAAO,IAAI,KAAK,CAAC,EAAO,EAAE;QACxB,GAAG,CAAC,MAAM,EAAE,IAAqB;YAC/B,+CAA+C;YAC/C,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC7B,OAAO,SAAS,CAAC;YACnB,CAAC;YAED,yCAAyC;YACzC,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACjC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,EAAE,CAAC,CAAC;YACvD,CAAC;YAED,gDAAgD;YAChD,OAAO,KAAK,EAAE,GAAG,IAAW,EAAE,EAAE;gBAC9B,OAAO,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;YACrD,CAAC,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,WAAW,CACxB,SAAuB,EACvB,MAAoB,EACpB,KAAoB,EACpB,IAAW;IAEX,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IAEnC,qBAAqB;IACrB,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC;IAEvC,gBAAgB;IAChB,MAAM,OAAO,GAA2B;QACtC,cAAc,EAAE,kBAAkB;QAClC,GAAG,MAAM,CAAC,OAAO;KAClB,CAAC;IAEF,wBAAwB;IACxB,MAAM,OAAO,GAAgB;QAC3B,MAAM,EAAE,UAAU;QAClB,OAAO;KACR,CAAC;IAEF,wDAAwD;IACxD,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrE,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACzC,CAAC;IAED,wBAAwB;IACxB,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAE/C,wBAAwB;IACxB,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,QAAQ,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,KAAK,SAAS,EAAE,CAChE,CAAC;IACJ,CAAC;IAED,qCAAqC;IACrC,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC"}
package/src/index.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @webpieces/http-client
3
+ *
4
+ * Client-side HTTP client generation package.
5
+ * Reads API decorators and generates type-safe HTTP clients.
6
+ *
7
+ * This is the client-side counterpart to @webpieces/http-routing:
8
+ * - Server (@webpieces/http-routing): API decorators → route HTTP to controllers
9
+ * - Client (@webpieces/http-client): API decorators → generate HTTP from method calls
10
+ *
11
+ * Both packages depend on @webpieces/http-api for shared decorator definitions.
12
+ *
13
+ * Architecture:
14
+ * ```
15
+ * http-api (defines the contract)
16
+ * ↑
17
+ * ├── http-routing (server: contract → handlers)
18
+ * └── http-client (client: contract → HTTP requests) ← YOU ARE HERE
19
+ * ```
20
+ *
21
+ * Usage:
22
+ * ```typescript
23
+ * import { createClient } from '@webpieces/http-client';
24
+ * import { SaveApiPrototype } from './api/SaveApi';
25
+ *
26
+ * const client = createClient(SaveApiPrototype, {
27
+ * baseUrl: 'http://localhost:3000'
28
+ * });
29
+ *
30
+ * const response = await client.save({ query: 'test' });
31
+ * ```
32
+ */
33
+ export { createClient, ClientConfig } from './ClientFactory';
34
+ export { ApiInterface, Get, Post, Put, Delete, Patch, Path, ValidateImplementation, } from '@webpieces/http-api';
package/src/index.js ADDED
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ /**
3
+ * @webpieces/http-client
4
+ *
5
+ * Client-side HTTP client generation package.
6
+ * Reads API decorators and generates type-safe HTTP clients.
7
+ *
8
+ * This is the client-side counterpart to @webpieces/http-routing:
9
+ * - Server (@webpieces/http-routing): API decorators → route HTTP to controllers
10
+ * - Client (@webpieces/http-client): API decorators → generate HTTP from method calls
11
+ *
12
+ * Both packages depend on @webpieces/http-api for shared decorator definitions.
13
+ *
14
+ * Architecture:
15
+ * ```
16
+ * http-api (defines the contract)
17
+ * ↑
18
+ * ├── http-routing (server: contract → handlers)
19
+ * └── http-client (client: contract → HTTP requests) ← YOU ARE HERE
20
+ * ```
21
+ *
22
+ * Usage:
23
+ * ```typescript
24
+ * import { createClient } from '@webpieces/http-client';
25
+ * import { SaveApiPrototype } from './api/SaveApi';
26
+ *
27
+ * const client = createClient(SaveApiPrototype, {
28
+ * baseUrl: 'http://localhost:3000'
29
+ * });
30
+ *
31
+ * const response = await client.save({ query: 'test' });
32
+ * ```
33
+ */
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ exports.Path = exports.Patch = exports.Delete = exports.Put = exports.Post = exports.Get = exports.ApiInterface = exports.createClient = void 0;
36
+ var ClientFactory_1 = require("./ClientFactory");
37
+ Object.defineProperty(exports, "createClient", { enumerable: true, get: function () { return ClientFactory_1.createClient; } });
38
+ // Re-export API decorators for convenience (same as http-routing does)
39
+ var http_api_1 = require("@webpieces/http-api");
40
+ Object.defineProperty(exports, "ApiInterface", { enumerable: true, get: function () { return http_api_1.ApiInterface; } });
41
+ Object.defineProperty(exports, "Get", { enumerable: true, get: function () { return http_api_1.Get; } });
42
+ Object.defineProperty(exports, "Post", { enumerable: true, get: function () { return http_api_1.Post; } });
43
+ Object.defineProperty(exports, "Put", { enumerable: true, get: function () { return http_api_1.Put; } });
44
+ Object.defineProperty(exports, "Delete", { enumerable: true, get: function () { return http_api_1.Delete; } });
45
+ Object.defineProperty(exports, "Patch", { enumerable: true, get: function () { return http_api_1.Patch; } });
46
+ Object.defineProperty(exports, "Path", { enumerable: true, get: function () { return http_api_1.Path; } });
47
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/http/http-client/src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;;;AAEH,iDAA6D;AAApD,6GAAA,YAAY,OAAA;AAErB,uEAAuE;AACvE,gDAS6B;AAR3B,wGAAA,YAAY,OAAA;AACZ,+FAAA,GAAG,OAAA;AACH,gGAAA,IAAI,OAAA;AACJ,+FAAA,GAAG,OAAA;AACH,kGAAA,MAAM,OAAA;AACN,iGAAA,KAAK,OAAA;AACL,gGAAA,IAAI,OAAA"}