objective-http 1.3.0 → 2.0.1

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 (58) hide show
  1. package/README.md +102 -191
  2. package/package.json +43 -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 -6
  13. package/src/js/server/Server.js +42 -60
  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 -4
  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 -4
  34. package/src/js/bun/Bunttp.js +0 -28
  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 -50
  43. package/src/js/bun/server/request/index.js +0 -3
  44. package/src/js/bun/server/response/OutputResponse.js +0 -49
  45. package/src/js/bun/server/response/index.js +0 -3
  46. package/src/js/client/request/OutputRequest.js +0 -81
  47. package/src/js/client/response/InputResponse.js +0 -58
  48. package/src/js/server/LoggedServer.js +0 -30
  49. package/src/js/server/endpoint/Endpoint.js +0 -24
  50. package/src/js/server/endpoint/Endpoints.js +0 -26
  51. package/src/js/server/endpoint/LoggedEndpoint.js +0 -30
  52. package/src/js/server/endpoint/index.js +0 -5
  53. package/src/js/server/request/InputRequest.js +0 -58
  54. package/src/js/server/request/JsonInputRequest.js +0 -51
  55. package/src/js/server/request/LoggedInputRequest.js +0 -44
  56. package/src/js/server/response/JsonOutputResponse.js +0 -45
  57. package/src/js/server/response/LoggedOutputResponse.js +0 -36
  58. package/src/js/server/response/OutputResponse.js +0 -52
package/README.md CHANGED
@@ -1,60 +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
- LoggedEndpoint,
19
- 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
+ },
20
33
  },
21
34
  request: {
22
- InputRequest,
23
- JsonInputRequest,
24
- LoggedInputRequest,
35
+ chunk: { JsonServerRequest, ChunkServerRequest },
25
36
  },
26
37
  response: {
27
- OutputResponse,
28
- JsonOutputResponse,
29
- LoggedOutputResponse
30
- }
38
+ chunk: { JsonServerResponse, ChunkServerResponse },
39
+ },
31
40
  } = require('objective-http').server;
32
41
 
33
- new LoggedServer(
34
- new Server(
35
- new Endpoints([
36
- new LoggedEndpoint(new MyFirstEndpoint(), console),
37
- new LoggedEndpoint(new MySecondEndpoint(), console),
38
- new LoggedEndpoint(new MyThirdEndpoint(), console)
39
- ]),
40
- {port: server_port},
41
- new LoggedInputRequest(new JsonInputRequest(new InputRequest()), console),
42
- new LoggedOutputResponse(new JsonOutputResponse(new OutputResponse()), console),
43
- createServerFunction
44
- ),
45
- console
46
- ).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
+ });
47
88
  ```
48
89
 
49
90
  `MyEndpoint` class example:
50
91
 
51
92
  ```javascript
52
93
  class MyEndpoint {
53
- route() {
54
- return {
55
- method: 'GET',
56
- path: '/test'
57
- };
94
+ route = {
95
+ method: 'GET',
96
+ path: '/test'
58
97
  }
59
98
 
60
99
  async handle(request) {
@@ -62,13 +101,13 @@ class MyEndpoint {
62
101
  const processResult = await someProcess();
63
102
 
64
103
  return {
65
- statusCode: 200,
104
+ status: 200,
66
105
  body: processResult.toString()
67
106
  };
68
107
 
69
108
  } catch (e) {
70
109
  return {
71
- statusCode: 404,
110
+ status: 404,
72
111
  body: 'process does not found anything'
73
112
  };
74
113
  }
@@ -79,168 +118,40 @@ class MyEndpoint {
79
118
 
80
119
  ## Client
81
120
 
82
- ```javascript
83
- const requestFunction = require('node:http').request;
84
-
85
- const {
86
- request: {
87
- OutputRequest
88
- },
89
- response: {
90
- InputResponse
91
- }
92
- } = require('objective-http').client;
93
-
94
-
95
- const response = await new OutputRequest(
96
- new InputResponse(),
97
- requestFunction,
98
- {
99
- url: 'https://example.com',
100
- method: 'POST',
101
- body: 'test body'
102
- })
103
- .send();
104
-
105
- console.log(response.body().toString());
106
-
107
- //or
108
-
109
- const request = new OutputRequest(new InputResponse(), requestFunction);
110
-
111
- const otherResponse = await (request
112
- .copy({
113
- url: 'https://example.com',
114
- method: 'POST',
115
- body: 'test body'
116
- }))
117
- .send();
118
-
119
- console.log(response.body().toString());
120
- ```
121
-
122
-
123
- ## [Bun](https://bun.sh) support
124
-
125
- `server` and `client` packages support Bun by default.
126
- But there ara special `bun` package with native [Bun API](https://bun.sh/docs/runtime/bun-apis) implementation (like `Bun.serve()`).
127
- And you should replace `node:http` package with `objective-http.bun.bunttp` in your `Server` configuration.
128
-
129
-
130
- ### Server Bun usage
131
-
132
- It should work with `node` and `bun`:
121
+ Simple wrapper for requests. `options` passing into `http.request(oprions, ...)`
133
122
 
134
123
  ```javascript
135
- const createServerFunction = require('node:http').createServer;
136
-
124
+ const http = require('node:http');
137
125
  const {
138
- Server,
139
- LoggedServer,
140
- endpoint: {
141
- Endpoint,
142
- LoggedEndpoint,
143
- Endpoints
144
- },
145
126
  request: {
146
- InputRequest,
147
- JsonInputRequest,
148
- LoggedInputRequest,
127
+ chunk: { JsonClientRequest, ChunkClientRequest },
149
128
  },
150
129
  response: {
151
- OutputResponse,
152
- JsonOutputResponse,
153
- LoggedOutputResponse
154
- }
155
- } = require('objective-http').server;
156
-
157
- new LoggedServer(
158
- new Server(
159
- new Endpoints([
160
- new LoggedEndpoint(new MyFirstEndpoint(), console),
161
- new LoggedEndpoint(new MySecondEndpoint(), console),
162
- new LoggedEndpoint(new MyThirdEndpoint(), console)
163
- ]),
164
- {port: server_port},
165
- new LoggedInputRequest(new JsonInputRequest(new InputRequest()), console),
166
- new LoggedOutputResponse(new JsonOutputResponse(new OutputResponse()), console),
167
- createServerFunction
168
- ),
169
- console
170
- ).start()
171
- ```
172
-
173
- In order for the code to be executed only by `bun` (with `Bun API` inside), you need to make changes to the import block.
174
- `bun` package redeclare only `InputRequest` and `OutputResponse` classes. Other classes taken from `server` package.
175
-
176
- ```javascript
177
- const createServerFunction = require('objective-http').bun.bunttp.createServer;
178
-
179
- const {
180
- Server,
181
- LoggedServer,
182
- endpoint: {
183
- Endpoint,
184
- LoggedEndpoint,
185
- Endpoints
186
- },
187
- request: {
188
- JsonInputRequest,
189
- LoggedInputRequest,
190
- },
191
- response: {
192
- JsonOutputResponse,
193
- LoggedOutputResponse
194
- }
195
- } = require('objective-http').server;
196
-
197
- const {
198
- request: {
199
- InputRequest
200
- },
201
- response: {
202
- OutputResponse
203
- }
204
- } = require('objective-http').bun.server;
205
- ```
206
-
207
-
208
- ### Client Bun usage
209
-
210
- It should work with `node` and `bun`:
211
-
212
- ```javascript
213
- const requestFunction = require('node:http').request;
214
-
215
- const {
216
- request: {
217
- OutputRequest
130
+ chunk: { JsonClientResponse, ChunkClientResponse },
218
131
  },
219
- response: {
220
- InputResponse
221
- }
222
132
  } = require('objective-http').client;
223
133
 
224
- await (new OutputRequest(new InputResponse(), requestFunction)
225
- .copy({
226
- url: 'https://example.com',
227
- method: 'POST',
228
- body: 'test body'
229
- }))
230
- .send();
231
- ```
232
-
233
- 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()
234
154
 
235
- ```javascript
236
- const requestFunction = require('objective-http').bun.bunttp.request;
155
+ console.log(JSON.stringify(response.body));
156
+ ```
237
157
 
238
- const {
239
- request: {
240
- OutputRequest
241
- },
242
- response: {
243
- InputResponse
244
- }
245
- } = require('objective-http').bun.client;
246
- ```
package/package.json CHANGED
@@ -1 +1,43 @@
1
- {"name":"objective-http","version":"1.3.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.1",
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
+ "url": "git+https://github.com/volatilization/objective-http.git"
18
+ },
19
+ "license": "LGPL-3.0-only",
20
+ "scripts": {
21
+ "lint": "eslint",
22
+ "test": "node --test --experimental-test-coverage --test-reporter=spec src/test/*.js src/test/**/*.js",
23
+ "test:coverage": "node scripts/coverage.js",
24
+ "release": "release-it --config release-it.config.mjs",
25
+ "release:no-increment": "release-it --config release-it.config.mjs --no-increment",
26
+ "dist:build": "node scripts/build.js",
27
+ "dist:cleanup": "node scripts/cleanup.js"
28
+ },
29
+ "main": "src/js/index.js",
30
+ "devDependencies": {
31
+ "@dotenvx/dotenvx": "^1.57.5",
32
+ "@eslint/js": "^9.35.0",
33
+ "@eslint/json": "^0.12.0",
34
+ "@eslint/markdown": "^6.4.0",
35
+ "eslint": "^9.35.0",
36
+ "eslint-config-prettier": "^10.1.5",
37
+ "eslint-plugin-prettier": "^5.4.0",
38
+ "globals": "^16.0.0",
39
+ "prettier": "3.5.3",
40
+ "prettier-eslint-cli": "^8.0.1",
41
+ "release-it": "^19.2.4"
42
+ }
43
+ }
@@ -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,9 +1,4 @@
1
1
  module.exports = {
2
2
  server: require('./server'),
3
3
  client: require('./client'),
4
- bun: {
5
- server: {...require('./server'), ...require('./bun').server},
6
- client: {...require('./client'), ...require('./bun').client},
7
- bunttp: require('./bun').bunttp
8
- }
9
- }
4
+ };