objective-http 1.0.4 → 1.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 CHANGED
@@ -1,7 +1,10 @@
1
1
  # objective-http
2
2
  Proxy classes for creating a http server
3
3
 
4
- ## Using
4
+ ## Server
5
+
6
+ There are all ```Server``` classes feature.
7
+ Your endpoints must implement ```Endpoint``` class interface (```route``` and ```handle``` functions).
5
8
 
6
9
  ``` javascript
7
10
  const http = require('node:http');
@@ -40,4 +43,40 @@ new ClusteredServer(
40
43
  cluster,
41
44
  {workers: workers_count}
42
45
  ).start();
46
+ ```
47
+
48
+ ## Client
49
+
50
+ ``` javascript
51
+ const https = require('node:https');
52
+ const {
53
+ OutputRequest,
54
+ InputResponse
55
+ } = require('objective-http').client;
56
+
57
+
58
+ const response = await new OutputRequest(
59
+ https,
60
+ new InputResponse(),
61
+ {
62
+ url: 'https://example.com',
63
+ method: 'POST',
64
+ body: 'test body'
65
+ })
66
+ .send();
67
+
68
+ console.log(response.body().toString());
69
+
70
+ //or
71
+
72
+ const request = new OutputRequest(https, new InputResponse());
73
+
74
+ const otherResponse = await (request
75
+ .copy({
76
+ url: 'https://example.com',
77
+ method: 'POST',
78
+ body: 'test body'
79
+ }))
80
+ .send()
81
+
43
82
  ```
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"objective-http","version":"1.0.4","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
+ {"name":"objective-http","version":"1.1.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"}
@@ -0,0 +1,69 @@
1
+ module.exports = class OutputRequest {
2
+ #http;
3
+ #response;
4
+ #options;
5
+
6
+ constructor(http, response, options) {
7
+ this.#http = http;
8
+ this.#response = response;
9
+ this.#options = {method: 'GET', ...options};
10
+ }
11
+
12
+ copy(options = this.#options, response = this.#response, http = this.#http) {
13
+ return new OutputRequest(http, response, {method: 'GET', ...options});
14
+ }
15
+
16
+ send() {
17
+ return new Promise((resolve, reject) => {
18
+ try {
19
+ this.#sendRequestOutputStream(
20
+ this.#configureRequestOutputStream(this.#http, this.#response, this.#options, resolve, reject),
21
+ this.#options);
22
+
23
+ } catch (e) {
24
+ throw new Error(e.message, {cause: 'INVALID_REQUEST'});
25
+ }
26
+ });
27
+ }
28
+
29
+ #configureRequestOutputStream(http, response, options, resolve, reject) {
30
+ if (options.url != null) {
31
+ return http.request(
32
+ options.url,
33
+ options,
34
+ async (responseInputStream) => {
35
+ await this.#flushResponseInputStream(responseInputStream, response, resolve, reject);
36
+ });
37
+ }
38
+
39
+ return http.request(
40
+ options,
41
+ async (responseInputStream) => {
42
+ await this.#flushResponseInputStream(responseInputStream, response, resolve, reject);
43
+ });
44
+ }
45
+
46
+ async #flushResponseInputStream(responseInputStream, response, resolve, reject) {
47
+ try {
48
+ resolve(await response
49
+ .copy(responseInputStream)
50
+ .flush());
51
+
52
+ } catch (e) {
53
+ reject(e);
54
+ }
55
+ }
56
+
57
+ #sendRequestOutputStream(requestOutputStream, options) {
58
+ if (this.#needToByWritten(options)) {
59
+ requestOutputStream.write(options.body);
60
+ }
61
+
62
+ requestOutputStream.end();
63
+ }
64
+
65
+ #needToByWritten(options) {
66
+ return ['POST', 'PUT'].some(method => method === options.method.toString().toUpperCase())
67
+ && (options.body != null && typeof options.body === 'string');
68
+ }
69
+ };
@@ -0,0 +1,43 @@
1
+ module.exports = class InputResponse {
2
+ #inputStream;
3
+ #options;
4
+
5
+ constructor(inputStream, options) {
6
+ this.#inputStream = inputStream;
7
+ this.#options = options;
8
+ }
9
+
10
+ copy(inputStream = this.#inputStream, options = this.#options) {
11
+ return new InputResponse(inputStream, options);
12
+ }
13
+
14
+ flush() {
15
+ return new Promise((resolve, reject) => {
16
+ this.#inputStream.once('error', (e) =>
17
+ reject(new Error(e.message, {cause: 'INVALID_RESPONSE'}))
18
+ );
19
+
20
+ let chunks = [];
21
+ this.#inputStream.on('data', (chunk) => chunks.push(chunk));
22
+ this.#inputStream.on('end', () => resolve(new InputResponse(this.#inputStream,
23
+ {
24
+ statusCode: this.#inputStream.statusCode,
25
+ headers: new Headers(this.#inputStream.headers),
26
+ body: Buffer.concat(chunks)
27
+ }
28
+ )));
29
+ });
30
+ }
31
+
32
+ statusCode() {
33
+ return this.#options.statusCode;
34
+ }
35
+
36
+ headers() {
37
+ return this.#options.headers;
38
+ }
39
+
40
+ body() {
41
+ return this.#options.body;
42
+ }
43
+ };
package/src/js/index.js CHANGED
@@ -12,5 +12,9 @@ module.exports = {
12
12
  OutputResponse: require('./server/response/OutputResponse'),
13
13
  JsonOutputResponse: require('./server/response/JsonOutputResponse'),
14
14
  LoggedOutputResponse: require('./server/response/LoggedOutputResponse')
15
+ },
16
+ client: {
17
+ OutputRequest: require('./client/request/OutputRequest'),
18
+ InputResponse: require('./client/response/InputResponse')
15
19
  }
16
20
  }
@@ -12,23 +12,22 @@ module.exports = class InputRequest {
12
12
  }
13
13
 
14
14
  flush() {
15
- return new Promise((resolve) => {
16
- this.#inputStream.once('error', (e) => {
17
- throw new Error(e.message, {cause: 'INVALID_REQUEST'});
18
- });
19
-
20
- if (!this.#isChunkedInputStream(this.#inputStream)) {
21
- return resolve(new InputRequest(
22
- this.#inputStream,
23
- this.#extractOptionsFromInputStream(this.#inputStream)
24
- ));
25
- }
15
+ return new Promise((resolve, reject) => {
16
+ this.#inputStream.once('error', (e) =>
17
+ reject(new Error(e.message, {cause: 'INVALID_REQUEST'}))
18
+ );
26
19
 
27
20
  let chunks = [];
28
21
  this.#inputStream.on('data', (chunk) => chunks.push(chunk));
29
22
  this.#inputStream.on('end', () => resolve(new InputRequest(
30
23
  this.#inputStream,
31
- {... this.#extractOptionsFromInputStream(this.#inputStream), body: Buffer.concat(chunks)}
24
+ {
25
+ method: this.#inputStream.method,
26
+ path: new URL(this.#inputStream.url, 'http://dummy').pathname,
27
+ query: new URL(this.#inputStream.url, 'http://dummy').searchParams,
28
+ headers: new Headers(this.#inputStream.headers),
29
+ body: Buffer.concat(chunks)
30
+ }
32
31
  )));
33
32
  });
34
33
  }
@@ -37,7 +36,7 @@ module.exports = class InputRequest {
37
36
  return {
38
37
  method: this.#options.method.toString().toUpperCase(),
39
38
  path: this.#options.path.toString().toLowerCase()
40
- }
39
+ };
41
40
  }
42
41
 
43
42
  query() {
@@ -51,17 +50,4 @@ module.exports = class InputRequest {
51
50
  headers() {
52
51
  return this.#options.headers;
53
52
  }
54
-
55
- #isChunkedInputStream(inputStream) {
56
- return ['POST', 'PUT'].some(method => method === inputStream.method.toString().toUpperCase());
57
- }
58
-
59
- #extractOptionsFromInputStream(inputStream) {
60
- return {
61
- method: inputStream.method,
62
- path: new URL(inputStream.url, 'http://dummy').pathname,
63
- query: new URL(inputStream.url, 'http://dummy').searchParams,
64
- headers: inputStream.headers
65
- };
66
- }
67
- }
53
+ };
@@ -28,10 +28,6 @@ module.exports = class JsonInputRequest {
28
28
  }
29
29
 
30
30
  body() {
31
- if (this.#origin.body() == null) {
32
- return null;
33
- }
34
-
35
31
  try {
36
32
  return JSON.parse(this.#origin.body().toString());
37
33