objective-http 1.4.0 → 2.0.2

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.

Potentially problematic release.


This version of objective-http might be problematic. Click here for more details.

Files changed (55) hide show
  1. package/README.md +102 -182
  2. package/package.json +44 -1
  3. package/src/js/client/index.js +2 -2
  4. package/src/js/client/request/chunk/ChunkClientRequest.js +67 -0
  5. package/src/js/client/request/chunk/JsonClientRequest.js +55 -0
  6. package/src/js/client/request/chunk/index.js +4 -0
  7. package/src/js/client/request/index.js +2 -2
  8. package/src/js/client/response/chunk/ChunkClientResponse.js +75 -0
  9. package/src/js/client/response/chunk/JsonClientResponse.js +62 -0
  10. package/src/js/client/response/chunk/index.js +4 -0
  11. package/src/js/client/response/index.js +2 -2
  12. package/src/js/index.js +1 -2
  13. package/src/js/server/Server.js +40 -62
  14. package/src/js/server/handler/endpoint/EndpointHandler.js +35 -0
  15. package/src/js/server/handler/endpoint/EndpointHandlers.js +22 -0
  16. package/src/js/server/handler/endpoint/EndpointsHandler.js +42 -0
  17. package/src/js/server/handler/endpoint/EndpontRequiredHandler.js +22 -0
  18. package/src/js/server/handler/endpoint/index.js +6 -0
  19. package/src/js/server/handler/error/HandlerNotFoundErrorHandler.js +27 -0
  20. package/src/js/server/handler/error/InvalidRequestErrorHandler.js +27 -0
  21. package/src/js/server/handler/error/LogErrorHandler.js +21 -0
  22. package/src/js/server/handler/error/UnexpectedErrorHandler.js +23 -0
  23. package/src/js/server/handler/error/index.js +6 -0
  24. package/src/js/server/handler/index.js +4 -0
  25. package/src/js/server/index.js +3 -4
  26. package/src/js/server/request/chunk/ChunkServerRequest.js +87 -0
  27. package/src/js/server/request/chunk/JsonServerRequest.js +67 -0
  28. package/src/js/server/request/chunk/index.js +4 -0
  29. package/src/js/server/request/index.js +2 -3
  30. package/src/js/server/response/chunk/ChunkServerResponse.js +53 -0
  31. package/src/js/server/response/chunk/JsonServerResponse.js +50 -0
  32. package/src/js/server/response/chunk/index.js +4 -0
  33. package/src/js/server/response/index.js +2 -3
  34. package/src/js/bun/Bunttp.js +0 -25
  35. package/src/js/bun/client/index.js +0 -4
  36. package/src/js/bun/client/request/OutputRequest.js +0 -26
  37. package/src/js/bun/client/request/index.js +0 -3
  38. package/src/js/bun/client/response/InputResponse.js +0 -40
  39. package/src/js/bun/client/response/index.js +0 -3
  40. package/src/js/bun/index.js +0 -5
  41. package/src/js/bun/server/index.js +0 -4
  42. package/src/js/bun/server/request/InputRequest.js +0 -49
  43. package/src/js/bun/server/request/index.js +0 -3
  44. package/src/js/bun/server/response/OutputResponse.js +0 -25
  45. package/src/js/bun/server/response/index.js +0 -3
  46. package/src/js/client/request/OutputRequest.js +0 -53
  47. package/src/js/client/response/InputResponse.js +0 -48
  48. package/src/js/server/LoggedServer.js +0 -29
  49. package/src/js/server/endpoint/Endpoint.js +0 -17
  50. package/src/js/server/endpoint/Endpoints.js +0 -36
  51. package/src/js/server/endpoint/index.js +0 -4
  52. package/src/js/server/request/InputRequest.js +0 -57
  53. package/src/js/server/request/LoggedInputRequest.js +0 -44
  54. package/src/js/server/response/LoggedOutputResponse.js +0 -32
  55. package/src/js/server/response/OutputResponse.js +0 -28
package/README.md CHANGED
@@ -1,57 +1,99 @@
1
+
1
2
  # objective-http
2
- Proxy classes for creating a http server
3
3
 
4
+ Proxy classes for creating a http server
4
5
 
5
6
  ## Server
6
7
 
7
8
  There are all `Server` classes feature.
8
- Your endpoints must implement `Endpoint` class interface (`route()` and `async handle(request)` methods).
9
+ Your endpoints should implement `Endpoint` class interface
10
+ (`get route()` and `async handle(request)` methods).
11
+ Also you can add own handlers (`handle(reqestStream, responseStream)`).
12
+ `Handler` is a top level logic object, who intrreact with IO streams directly.
13
+ `options` is a `node:http` options, who pass when server starting.
9
14
 
10
15
  ```javascript
11
- const createServerFunction = require('node:http').createServer;
12
-
16
+ const http = require('node:http');
17
+ const console = require('node:console');
13
18
  const {
14
19
  Server,
15
- LoggedServer,
16
- endpoint: {
17
- Endpoint,
18
- Endpoints
20
+ handler: {
21
+ endpoint: {
22
+ EndpointHandler,
23
+ EndpointsHandler,
24
+ EndpointHandlers,
25
+ EndpointRequiredHandler,
26
+ },
27
+ error: {
28
+ LogErrorHandler,
29
+ UnexpectedErrorHandler,
30
+ InvalidRequestErrorHandler,
31
+ HandlerNotFoundErrorHandler,
32
+ },
19
33
  },
20
34
  request: {
21
- InputRequest,
22
- LoggedInputRequest,
35
+ chunk: { JsonServerRequest, ChunkServerRequest },
23
36
  },
24
37
  response: {
25
- OutputResponse,
26
- LoggedOutputResponse
27
- }
38
+ chunk: { JsonServerResponse, ChunkServerResponse },
39
+ },
28
40
  } = require('objective-http').server;
29
41
 
30
- new LoggedServer(
31
- new Server(
32
- new Endpoints([
33
- new MyFirstEndpoint(),
34
- new MySecondEndpoint(),
35
- new MyThirdEndpoint()
36
- ]),
37
- {port: server_port},
38
- new LoggedInputRequest(new InputRequest(), console),
39
- new LoggedOutputResponse(new OutputResponse(), console),
40
- createServerFunction
41
- ),
42
- console
43
- ).start();
42
+ new Server({
43
+ handler: new UnexpectedErrorHandler({
44
+ origin: new LogErrorHandler({
45
+ origin: new InvalidRequestErrorHandler({
46
+ origin: new HandlerNotFoundErrorHandler({
47
+ origin: new EndpointRequiredHandler({
48
+ origin: new EndpointHandlers({
49
+ handlers: [
50
+ new EndpointHandler({
51
+ endpoint: new MyEndpoint(),
52
+ request: new ChunkServerRequest({}),
53
+ response: new ChunkServerResponse({}),
54
+ }),
55
+ new EndpointHandler({
56
+ endpoint: new MyEndpoint(),
57
+ request: new ChunkServerRequest({}),
58
+ response: new ChunkServerResponse({})
59
+ }),
60
+ new EndpointsHandler({
61
+ endpoints: [
62
+ new MyJsonEndpoint(),
63
+ new MyJsonEndpoint(),
64
+ new MyJsonEndpoint(),
65
+ ],
66
+ request: new JsonServerRequest({
67
+ origin: new ChunkServerRequest({}),
68
+ }),
69
+ response: new JsonServerResponse({
70
+ origin: new ChunkServerResponse({}),
71
+ }),
72
+ }),
73
+ ],
74
+ }),
75
+ }),
76
+ response: new ChunkServerResponse({}),
77
+ }),
78
+ response: new ChunkServerResponse({}),
79
+ }),
80
+ logger: console,
81
+ }),
82
+ response: new ChunkServerResponse({}),
83
+ }),
84
+
85
+ options: { port: 8080 },
86
+ http,
87
+ });
44
88
  ```
45
89
 
46
90
  `MyEndpoint` class example:
47
91
 
48
92
  ```javascript
49
93
  class MyEndpoint {
50
- route() {
51
- return {
52
- method: 'GET',
53
- path: '/test'
54
- };
94
+ route = {
95
+ method: 'GET',
96
+ path: '/test'
55
97
  }
56
98
 
57
99
  async handle(request) {
@@ -59,13 +101,13 @@ class MyEndpoint {
59
101
  const processResult = await someProcess();
60
102
 
61
103
  return {
62
- statusCode: 200,
104
+ status: 200,
63
105
  body: processResult.toString()
64
106
  };
65
107
 
66
108
  } catch (e) {
67
109
  return {
68
- statusCode: 404,
110
+ status: 404,
69
111
  body: 'process does not found anything'
70
112
  };
71
113
  }
@@ -76,162 +118,40 @@ class MyEndpoint {
76
118
 
77
119
  ## Client
78
120
 
79
- ```javascript
80
- const requestFunction = require('node:http').request;
81
-
82
- const {
83
- request: {
84
- OutputRequest
85
- },
86
- response: {
87
- InputResponse
88
- }
89
- } = require('objective-http').client;
90
-
91
-
92
- const response = await new OutputRequest(
93
- new InputResponse(),
94
- requestFunction,
95
- {
96
- url: 'https://example.com',
97
- method: 'POST',
98
- body: 'test body'
99
- })
100
- .send();
101
-
102
- console.log(response.body().toString());
103
-
104
- //or
105
-
106
- const request = new OutputRequest(new InputResponse(), requestFunction);
107
-
108
- const otherResponse = await (request
109
- .copy({
110
- url: 'https://example.com',
111
- method: 'POST',
112
- body: 'test body'
113
- }))
114
- .send();
115
-
116
- console.log(response.body().toString());
117
- ```
118
-
119
-
120
- ## [Bun](https://bun.sh) support
121
-
122
- `server` and `client` packages support Bun by default.
123
- But there ara special `bun` package with native [Bun API](https://bun.sh/docs/runtime/bun-apis) implementation (like `Bun.serve()`).
124
- And you should replace `node:http` package with `objective-http.bun.bunttp` in your `Server` configuration.
125
-
126
-
127
- ### Server Bun usage
128
-
129
- It should work with `node` and `bun`:
121
+ Simple wrapper for requests. `options` passing into `http.request(oprions, ...)`
130
122
 
131
123
  ```javascript
132
- const createServerFunction = require('node:http').createServer;
133
-
124
+ const http = require('node:http');
134
125
  const {
135
- Server,
136
- LoggedServer,
137
- endpoint: {
138
- Endpoint,
139
- Endpoints
140
- },
141
126
  request: {
142
- InputRequest,
143
- LoggedInputRequest,
127
+ chunk: { JsonClientRequest, ChunkClientRequest },
144
128
  },
145
129
  response: {
146
- OutputResponse,
147
- LoggedOutputResponse
148
- }
149
- } = require('objective-http').server;
150
-
151
- new LoggedServer(
152
- new Server(
153
- new Endpoints([
154
- new MyFirstEndpoint(),
155
- new MySecondEndpoint(),
156
- new MyThirdEndpoint()
157
- ]),
158
- {port: server_port},
159
- new LoggedInputRequest(new InputRequest(), console),
160
- new LoggedOutputResponse(new OutputResponse(), console),
161
- createServerFunction
162
- ),
163
- console
164
- ).start()
165
- ```
166
-
167
- In order for the code to be executed only by `bun` (with `Bun API` inside), you need to make changes to the import block.
168
- `bun` package redeclare only `InputRequest` and `OutputResponse` classes. Other classes taken from `server` package.
169
-
170
- ```javascript
171
- const createServerFunction = require('objective-http').bun.bunttp.createServer;
172
-
173
- const {
174
- Server,
175
- LoggedServer,
176
- endpoint: {
177
- Endpoint,
178
- Endpoints
179
- },
180
- request: {
181
- LoggedInputRequest,
182
- },
183
- response: {
184
- LoggedOutputResponse
185
- }
186
- } = require('objective-http').server;
187
-
188
- const {
189
- request: {
190
- InputRequest
191
- },
192
- response: {
193
- OutputResponse
194
- }
195
- } = require('objective-http').bun.server;
196
- ```
197
-
198
-
199
- ### Client Bun usage
200
-
201
- It should work with `node` and `bun`:
202
-
203
- ```javascript
204
- const requestFunction = require('node:http').request;
205
-
206
- const {
207
- request: {
208
- OutputRequest
130
+ chunk: { JsonClientResponse, ChunkClientResponse },
209
131
  },
210
- response: {
211
- InputResponse
212
- }
213
132
  } = require('objective-http').client;
214
133
 
215
- await (new OutputRequest(new InputResponse(), requestFunction)
216
- .copy({
217
- url: 'https://example.com',
218
- method: 'POST',
219
- body: 'test body'
220
- }))
221
- .send();
222
- ```
223
-
224
- In order for the code to be executed only by `bun`, you need to make changes to the import block.
134
+ const request = new JsonClientRequest({
135
+ origin: new ChunkClientRequest({
136
+ http: http,
137
+ response: new JsonClientResponse({
138
+ origin: new ChunkClientResponse({})
139
+ }),
140
+ }),
141
+ });
142
+
143
+ const response = await request
144
+ .with({
145
+ options: {
146
+ host: 'localhost',
147
+ port: 80,
148
+ method: 'GET',
149
+ path: '/test',
150
+ },
151
+ body: { some: 'body' }
152
+ })
153
+ .send()
225
154
 
226
- ```javascript
227
- const requestFunction = require('objective-http').bun.bunttp.request;
155
+ console.log(JSON.stringify(response.body));
156
+ ```
228
157
 
229
- const {
230
- request: {
231
- OutputRequest
232
- },
233
- response: {
234
- InputResponse
235
- }
236
- } = require('objective-http').bun.client;
237
- ```
package/package.json CHANGED
@@ -1 +1,44 @@
1
- {"name":"objective-http","version":"1.4.0","description":"Proxy classes for creating a http server","keywords":["web","web-server","http","http-server","oop"],"author":{"name":"volatilization","email":"volatilization@yandex.ru"},"repository":{"url":"git+https://github.com/volatilization/objective-http.git"},"license":"LGPL-3.0-only","main":"src/js/index.js"}
1
+ {
2
+ "name": "objective-http",
3
+ "version": "2.0.2",
4
+ "description": "Proxy classes for creating a http server",
5
+ "keywords": [
6
+ "web",
7
+ "web-server",
8
+ "http",
9
+ "http-server",
10
+ "oop"
11
+ ],
12
+ "author": {
13
+ "name": "volatilization",
14
+ "email": "volatilization@yandex.ru"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/volatilization/objective-http"
19
+ },
20
+ "license": "LGPL-3.0-only",
21
+ "scripts": {
22
+ "lint": "eslint",
23
+ "test": "node --test --experimental-test-coverage --test-reporter=spec src/test/*.js src/test/**/*.js",
24
+ "test:coverage": "node scripts/coverage.js",
25
+ "release": "release-it --config release-it.config.mjs",
26
+ "release:no-increment": "release-it --config release-it.config.mjs --no-increment",
27
+ "dist:build": "node scripts/build.js",
28
+ "dist:cleanup": "node scripts/cleanup.js"
29
+ },
30
+ "main": "src/js/index.js",
31
+ "devDependencies": {
32
+ "@dotenvx/dotenvx": "^1.57.5",
33
+ "@eslint/js": "^9.35.0",
34
+ "@eslint/json": "^0.12.0",
35
+ "@eslint/markdown": "^6.4.0",
36
+ "eslint": "^9.35.0",
37
+ "eslint-config-prettier": "^10.1.5",
38
+ "eslint-plugin-prettier": "^5.4.0",
39
+ "globals": "^16.0.0",
40
+ "prettier": "3.5.3",
41
+ "prettier-eslint-cli": "^8.0.1",
42
+ "release-it": "^19.2.4"
43
+ }
44
+ }
@@ -1,4 +1,4 @@
1
1
  module.exports = {
2
2
  request: require('./request'),
3
- response: require('./response')
4
- }
3
+ response: require('./response'),
4
+ };
@@ -0,0 +1,67 @@
1
+ module.exports = class ChunkClientRequest {
2
+ #http;
3
+ #options;
4
+ #body;
5
+ #response;
6
+
7
+ constructor({ http, options, body, response }) {
8
+ this.#http = http;
9
+ this.#options = options;
10
+ this.#body = body;
11
+ this.#response = response;
12
+ }
13
+
14
+ with({
15
+ http = this.#http,
16
+ options = this.#options,
17
+ body = this.#body,
18
+ response = this.#response,
19
+ }) {
20
+ return new ChunkClientRequest({ http, options, body, response });
21
+ }
22
+
23
+ get http() {
24
+ return this.#http;
25
+ }
26
+
27
+ get options() {
28
+ return this.#options;
29
+ }
30
+
31
+ get body() {
32
+ return this.#body;
33
+ }
34
+
35
+ get response() {
36
+ return this.#response;
37
+ }
38
+
39
+ send() {
40
+ return new Promise((resolve, reject) => {
41
+ const requestStream = this.http.request(
42
+ this.options,
43
+ (responseStream) => {
44
+ this.response
45
+ .with({ responseStream })
46
+ .accept()
47
+ .then(resolve)
48
+ .catch(reject);
49
+ },
50
+ );
51
+
52
+ requestStream.on('error', (e) => {
53
+ reject(
54
+ new Error('Client request error', {
55
+ cause: { error: e, code: 'REQUEST_ERROR' },
56
+ }),
57
+ );
58
+ });
59
+
60
+ if (this.body != null) {
61
+ requestStream.write(this.body);
62
+ }
63
+
64
+ requestStream.end();
65
+ });
66
+ }
67
+ };
@@ -0,0 +1,55 @@
1
+ module.exports = class JsonClientRequest {
2
+ #origin;
3
+
4
+ constructor({ origin }) {
5
+ this.#origin = origin;
6
+ }
7
+
8
+ with({
9
+ http,
10
+ options,
11
+ body,
12
+ response,
13
+ origin = this.#origin.with({
14
+ http,
15
+ options,
16
+ body,
17
+ response,
18
+ }),
19
+ }) {
20
+ return new JsonClientRequest({ origin });
21
+ }
22
+
23
+ get http() {
24
+ return this.#origin.http;
25
+ }
26
+
27
+ get options() {
28
+ return {
29
+ ...this.#origin.options,
30
+ headers: {
31
+ ...this.#origin.options.headers,
32
+ 'content-type': 'application/json',
33
+ },
34
+ };
35
+ }
36
+
37
+ get body() {
38
+ return this.#origin.body
39
+ ? JSON.stringify(this.#origin.body)
40
+ : this.#origin.body;
41
+ }
42
+
43
+ get response() {
44
+ return this.#origin.response;
45
+ }
46
+
47
+ send() {
48
+ return this.#origin
49
+ .with({
50
+ body: this.body,
51
+ options: this.options,
52
+ })
53
+ .send();
54
+ }
55
+ };
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ ChunkClientRequest: require('./ChunkClientRequest'),
3
+ JsonClientRequest: require('./JsonClientRequest'),
4
+ };
@@ -1,3 +1,3 @@
1
1
  module.exports = {
2
- OutputRequest: require('./OutputRequest')
3
- };
2
+ chunk: require('./chunk'),
3
+ };
@@ -0,0 +1,75 @@
1
+ module.exports = class ChunkClientResponse {
2
+ #responseStream;
3
+ #status;
4
+ #headers;
5
+ #body;
6
+
7
+ constructor({ responseStream, status, headers, body }) {
8
+ this.#responseStream = responseStream;
9
+ this.#status = status;
10
+ this.#headers = headers;
11
+ this.#body = body;
12
+ }
13
+
14
+ with({
15
+ responseStream = this.#responseStream,
16
+ status = this.#status,
17
+ headers = this.#headers,
18
+ body = this.#body,
19
+ }) {
20
+ return new ChunkClientResponse({
21
+ responseStream,
22
+ status,
23
+ headers,
24
+ body,
25
+ });
26
+ }
27
+
28
+ get status() {
29
+ return this.#status;
30
+ }
31
+
32
+ get headers() {
33
+ return this.#headers;
34
+ }
35
+
36
+ get body() {
37
+ return this.#body;
38
+ }
39
+
40
+ get ok() {
41
+ return Number(this.status) === 200;
42
+ }
43
+
44
+ accept() {
45
+ return new Promise((resolve, reject) => {
46
+ try {
47
+ this.#responseStream.on('error', (e) => {
48
+ reject(
49
+ new Error('Client response error', {
50
+ cause: { error: e, code: 'RESPONSE_ERROR' },
51
+ }),
52
+ );
53
+ });
54
+
55
+ var chunks = [];
56
+ this.#responseStream.on('data', (chunk) => chunks.push(chunk));
57
+ this.#responseStream.on('end', () => {
58
+ resolve(
59
+ this.with({
60
+ status: this.#responseStream.statusCode,
61
+ headers: new Headers(this.#responseStream.headers),
62
+ body: Buffer.concat(chunks),
63
+ }),
64
+ );
65
+ });
66
+ } catch (e) {
67
+ reject(
68
+ new Error('Client reponse error', {
69
+ cause: { error: e, code: 'RESPONSE_ERROR' },
70
+ }),
71
+ );
72
+ }
73
+ });
74
+ }
75
+ };
@@ -0,0 +1,62 @@
1
+ module.exports = class JsonClientResponse {
2
+ #origin;
3
+
4
+ constructor({ origin }) {
5
+ this.#origin = origin;
6
+ }
7
+
8
+ with({
9
+ responseStream,
10
+ status,
11
+ headers,
12
+ body,
13
+ origin = this.#origin.with({
14
+ responseStream,
15
+ status,
16
+ headers,
17
+ body,
18
+ }),
19
+ }) {
20
+ return new JsonClientResponse({ origin });
21
+ }
22
+
23
+ get ok() {
24
+ return this.#origin.ok;
25
+ }
26
+
27
+ get status() {
28
+ return this.#origin.status;
29
+ }
30
+
31
+ get headers() {
32
+ return this.#origin.headers;
33
+ }
34
+
35
+ get body() {
36
+ return this.#origin.body;
37
+ }
38
+
39
+ async accept() {
40
+ const accepted = await this.#origin.accept();
41
+
42
+ try {
43
+ return this.with({
44
+ origin: accepted.with({
45
+ body:
46
+ accepted.body?.length > 0
47
+ ? JSON.parse(accepted.body?.toString())
48
+ : accepted.body,
49
+ headers: Object.fromEntries(accepted.headers),
50
+ }),
51
+ });
52
+ } catch (e) {
53
+ if (!(e instanceof SyntaxError)) {
54
+ throw new Error('JSON client response error', {
55
+ cause: { error: e, code: 'RESPONSE_ERROR' },
56
+ });
57
+ }
58
+
59
+ throw e;
60
+ }
61
+ }
62
+ };
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ ChunkClientResponse: require('./ChunkClientResponse'),
3
+ JsonClientResponse: require('./JsonClientResponse'),
4
+ };
@@ -1,3 +1,3 @@
1
1
  module.exports = {
2
- InputResponse: require('./InputResponse')
3
- };
2
+ chunk: require('./chunk'),
3
+ };
package/src/js/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  module.exports = {
2
2
  server: require('./server'),
3
3
  client: require('./client'),
4
- bun: require('./bun')
5
- }
4
+ };