@readme/httpsnippet 3.0.3 → 3.1.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.
- package/LICENSE +1 -1
- package/README.md +1 -0
- package/package.json +3 -3
- package/src/targets/javascript/axios.js +9 -2
- package/src/targets/javascript/fetch.js +16 -0
- package/src/targets/node/axios.js +2 -2
- package/src/targets/node/fetch.js +16 -12
- package/src/targets/php/guzzle.js +2 -2
- package/src/targets/python/index.js +1 -2
- package/src/targets/python/requests.js +78 -16
- package/src/targets/r/httr.js +13 -17
- package/src/targets/python/python3.js +0 -80
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
The MIT License (MIT)
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2022 ReadMe (https://readme.com)
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -160,6 +160,7 @@ The main difference between this library and the upstream [httpsnippet](https://
|
|
|
160
160
|
* Contains a `harIsAlreadyEncoded` option on the core library to disable [escaping](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent) of cookies and query strings in URLs. Helpful if the HAR being supplied already has them escaped.
|
|
161
161
|
* PHP Guzzle snippets come with `require_once('vendor/autoload.php');` at the top of them.
|
|
162
162
|
* A full integration suite for testing out snippets the library creates.
|
|
163
|
+
* This library does not ship a Python client for [http.client](https://docs.python.org/3/library/http.client.html) due to its limitations in supporting file uploads.
|
|
163
164
|
|
|
164
165
|
### Running the integration suite
|
|
165
166
|
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "3.
|
|
2
|
+
"version": "3.1.2",
|
|
3
3
|
"name": "@readme/httpsnippet",
|
|
4
4
|
"description": "HTTP Request snippet generator for *most* languages",
|
|
5
5
|
"homepage": "https://github.com/readmeio/httpsnippet",
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@readme/eslint-config": "^8.0.2",
|
|
57
57
|
"eslint": "^8.3.0",
|
|
58
|
-
"glob": "^
|
|
59
|
-
"jest": "^
|
|
58
|
+
"glob": "^8.0.1",
|
|
59
|
+
"jest": "^28.0.3",
|
|
60
60
|
"prettier": "^2.5.0",
|
|
61
61
|
"require-directory": "^2.1.1"
|
|
62
62
|
},
|
|
@@ -36,7 +36,14 @@ module.exports = function (source, options) {
|
|
|
36
36
|
|
|
37
37
|
switch (source.postData.mimeType) {
|
|
38
38
|
case 'application/x-www-form-urlencoded':
|
|
39
|
-
|
|
39
|
+
code.push('const encodedParams = new URLSearchParams();');
|
|
40
|
+
source.postData.params.forEach(function (param) {
|
|
41
|
+
code.push(`encodedParams.set('${param.name}', '${param.value}');`);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
code.blank();
|
|
45
|
+
|
|
46
|
+
reqOpts.data = 'encodedParams';
|
|
40
47
|
break;
|
|
41
48
|
|
|
42
49
|
case 'application/json':
|
|
@@ -83,7 +90,7 @@ module.exports = function (source, options) {
|
|
|
83
90
|
.push(1, 'console.error(error);')
|
|
84
91
|
.push('});');
|
|
85
92
|
|
|
86
|
-
return code.join();
|
|
93
|
+
return code.join().replace(/'encodedParams'/, 'encodedParams,');
|
|
87
94
|
};
|
|
88
95
|
|
|
89
96
|
module.exports.info = {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
const stringifyObject = require('stringify-object');
|
|
12
12
|
const CodeBuilder = require('../../helpers/code-builder');
|
|
13
|
+
const { getHeaderName } = require('../../helpers/headers');
|
|
13
14
|
|
|
14
15
|
module.exports = function (source, options) {
|
|
15
16
|
const opts = {
|
|
@@ -45,6 +46,15 @@ module.exports = function (source, options) {
|
|
|
45
46
|
|
|
46
47
|
case 'multipart/form-data':
|
|
47
48
|
if (source.postData.params) {
|
|
49
|
+
// The FormData API automatically adds a `Content-Type` header for `multipart/form-data`
|
|
50
|
+
// content and if we add our own here data won't be correctly transmitted.
|
|
51
|
+
if (reqOptions.headers) {
|
|
52
|
+
const contentTypeHeader = getHeaderName(reqOptions.headers, 'content-type');
|
|
53
|
+
if (contentTypeHeader) {
|
|
54
|
+
delete reqOptions.headers[contentTypeHeader];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
48
58
|
code.push('const form = new FormData();');
|
|
49
59
|
|
|
50
60
|
source.postData.params.forEach(function (param) {
|
|
@@ -65,6 +75,12 @@ module.exports = function (source, options) {
|
|
|
65
75
|
}
|
|
66
76
|
}
|
|
67
77
|
|
|
78
|
+
// If we ultimately don't have any headers to send then we shouldn't add an empty object into the
|
|
79
|
+
// request options.
|
|
80
|
+
if (reqOptions.headers && !Object.keys(reqOptions.headers).length) {
|
|
81
|
+
delete reqOptions.headers;
|
|
82
|
+
}
|
|
83
|
+
|
|
68
84
|
code
|
|
69
85
|
.push(
|
|
70
86
|
'const options = %s;',
|
|
@@ -33,9 +33,9 @@ module.exports = function (source, options) {
|
|
|
33
33
|
switch (source.postData.mimeType) {
|
|
34
34
|
case 'application/x-www-form-urlencoded':
|
|
35
35
|
code.push("const { URLSearchParams } = require('url');");
|
|
36
|
-
code.push('const encodedParams = new URLSearchParams();');
|
|
37
36
|
code.blank();
|
|
38
37
|
|
|
38
|
+
code.push('const encodedParams = new URLSearchParams();');
|
|
39
39
|
source.postData.params.forEach(function (param) {
|
|
40
40
|
code.push(`encodedParams.set('${param.name}', '${param.value}');`);
|
|
41
41
|
});
|
|
@@ -65,7 +65,7 @@ module.exports = function (source, options) {
|
|
|
65
65
|
.push(1, 'console.error(error);')
|
|
66
66
|
.push('});');
|
|
67
67
|
|
|
68
|
-
return code.join().replace(/'encodedParams'/, 'encodedParams');
|
|
68
|
+
return code.join().replace(/'encodedParams'/, 'encodedParams,');
|
|
69
69
|
};
|
|
70
70
|
|
|
71
71
|
module.exports.info = {
|
|
@@ -27,18 +27,6 @@ module.exports = function (source, options) {
|
|
|
27
27
|
method: source.method,
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
// The `form-data` library automatically adds a `Content-Type` header for `multipart/form-data` content and if we
|
|
31
|
-
// add our own here, data won't be correctly transferred.
|
|
32
|
-
if (source.postData.mimeType === 'multipart/form-data') {
|
|
33
|
-
if (source.postData.params) {
|
|
34
|
-
const contentTypeHeader = headerHelpers.getHeaderName(source.allHeaders, 'content-type');
|
|
35
|
-
if (contentTypeHeader) {
|
|
36
|
-
// eslint-disable-next-line no-param-reassign
|
|
37
|
-
delete source.allHeaders[contentTypeHeader];
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
30
|
if (Object.keys(source.allHeaders).length) {
|
|
43
31
|
reqOpts.headers = source.allHeaders;
|
|
44
32
|
}
|
|
@@ -64,6 +52,16 @@ module.exports = function (source, options) {
|
|
|
64
52
|
|
|
65
53
|
case 'multipart/form-data':
|
|
66
54
|
if (source.postData.params) {
|
|
55
|
+
// The `form-data` library automatically adds a `Content-Type` header for
|
|
56
|
+
// `multipart/form-data` content and if we add our own here, data won't be correctly
|
|
57
|
+
// transferred.
|
|
58
|
+
if (reqOpts.headers) {
|
|
59
|
+
const contentTypeHeader = headerHelpers.getHeaderName(reqOpts.headers, 'content-type');
|
|
60
|
+
if (contentTypeHeader) {
|
|
61
|
+
delete reqOpts.headers[contentTypeHeader];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
67
65
|
code.unshift("const FormData = require('form-data');");
|
|
68
66
|
code.push('const formData = new FormData();');
|
|
69
67
|
code.blank();
|
|
@@ -88,6 +86,12 @@ module.exports = function (source, options) {
|
|
|
88
86
|
}
|
|
89
87
|
}
|
|
90
88
|
|
|
89
|
+
// If we ultimately don't have any headers to send then we shouldn't add an empty object into
|
|
90
|
+
// the request options.
|
|
91
|
+
if (reqOpts.headers && !Object.keys(reqOpts.headers).length) {
|
|
92
|
+
delete reqOpts.headers;
|
|
93
|
+
}
|
|
94
|
+
|
|
91
95
|
code.blank();
|
|
92
96
|
code.push(`const url = '${url}';`);
|
|
93
97
|
code
|
|
@@ -129,7 +129,7 @@ module.exports = function (source, options) {
|
|
|
129
129
|
|
|
130
130
|
module.exports.info = {
|
|
131
131
|
key: 'guzzle',
|
|
132
|
-
title: 'Guzzle
|
|
132
|
+
title: 'Guzzle',
|
|
133
133
|
link: 'http://docs.guzzlephp.org/en/stable/',
|
|
134
|
-
description: 'PHP with guzzle
|
|
134
|
+
description: 'PHP with guzzle',
|
|
135
135
|
};
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
const { format } = require('util');
|
|
12
12
|
const CodeBuilder = require('../../helpers/code-builder');
|
|
13
13
|
const helpers = require('./helpers');
|
|
14
|
+
const headerHelpers = require('../../helpers/headers');
|
|
14
15
|
|
|
15
16
|
module.exports = function (source, options) {
|
|
16
17
|
const opts = {
|
|
@@ -28,28 +29,74 @@ module.exports = function (source, options) {
|
|
|
28
29
|
// Set URL
|
|
29
30
|
code.push('url = "%s"', source.fullUrl).blank();
|
|
30
31
|
|
|
32
|
+
const headers = source.allHeaders;
|
|
33
|
+
|
|
31
34
|
// Construct payload
|
|
35
|
+
let payload;
|
|
36
|
+
let hasFiles = false;
|
|
32
37
|
let hasPayload = false;
|
|
33
38
|
let jsonPayload = false;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
switch (source.postData.mimeType) {
|
|
40
|
+
case 'application/json':
|
|
41
|
+
if (source.postData.jsonObj) {
|
|
42
|
+
code.push('payload = %s', helpers.literalRepresentation(source.postData.jsonObj, opts));
|
|
43
|
+
jsonPayload = true;
|
|
44
|
+
hasPayload = true;
|
|
45
|
+
}
|
|
46
|
+
break;
|
|
47
|
+
|
|
48
|
+
case 'multipart/form-data':
|
|
49
|
+
if (source.postData.params) {
|
|
50
|
+
const files = {};
|
|
51
|
+
payload = {};
|
|
52
|
+
|
|
53
|
+
source.postData.params.forEach(p => {
|
|
54
|
+
if (p.fileName) {
|
|
55
|
+
files[p.name] = `open('${p.fileName}', 'rb')`;
|
|
56
|
+
hasFiles = true;
|
|
57
|
+
} else {
|
|
58
|
+
payload[p.name] = p.value;
|
|
59
|
+
hasPayload = true;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
if (hasFiles) {
|
|
64
|
+
code.push('files = %s', helpers.literalRepresentation(files, opts));
|
|
65
|
+
|
|
66
|
+
if (hasPayload) {
|
|
67
|
+
code.push('payload = %s', helpers.literalRepresentation(payload, opts));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// The requests library will only automatically add a `multipart/form-data` header if
|
|
71
|
+
// there are files being sent. If we're **only** sending form data we still need to send
|
|
72
|
+
// the boundary ourselves.
|
|
73
|
+
delete headers[headerHelpers.getHeaderName(headers, 'content-type')];
|
|
74
|
+
} else {
|
|
75
|
+
payload = JSON.stringify(source.postData.text);
|
|
76
|
+
if (payload) {
|
|
77
|
+
code.push('payload = %s', payload);
|
|
78
|
+
hasPayload = true;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
break;
|
|
83
|
+
|
|
84
|
+
default:
|
|
85
|
+
payload = JSON.stringify(source.postData.text);
|
|
86
|
+
if (payload) {
|
|
87
|
+
code.push('payload = %s', payload);
|
|
88
|
+
hasPayload = true;
|
|
89
|
+
}
|
|
46
90
|
}
|
|
47
91
|
|
|
48
92
|
// Construct headers
|
|
49
|
-
const headers = source.allHeaders;
|
|
50
93
|
const headerCount = Object.keys(headers).length;
|
|
51
94
|
|
|
52
|
-
if (headerCount
|
|
95
|
+
if (!headerCount && (hasPayload || hasFiles)) {
|
|
96
|
+
// If we don't have any heads but we do have a payload we should put a blank line here between
|
|
97
|
+
// that payload consturction and our execution of the requests library.
|
|
98
|
+
code.blank();
|
|
99
|
+
} else if (headerCount === 1) {
|
|
53
100
|
Object.keys(headers).forEach(header => {
|
|
54
101
|
code.push('headers = {"%s": "%s"}', header, headers[header]).blank();
|
|
55
102
|
});
|
|
@@ -72,7 +119,13 @@ module.exports = function (source, options) {
|
|
|
72
119
|
|
|
73
120
|
// Construct request
|
|
74
121
|
const method = source.method;
|
|
75
|
-
let request
|
|
122
|
+
let request;
|
|
123
|
+
// Method list pulled from their api reference https://docs.python-requests.org/en/latest/api/#requests.head
|
|
124
|
+
if (['HEAD', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) {
|
|
125
|
+
request = format('response = requests.%s(url', method.toLowerCase());
|
|
126
|
+
} else {
|
|
127
|
+
request = format('response = requests.request("%s", url', method);
|
|
128
|
+
}
|
|
76
129
|
|
|
77
130
|
if (hasPayload) {
|
|
78
131
|
if (jsonPayload) {
|
|
@@ -82,6 +135,10 @@ module.exports = function (source, options) {
|
|
|
82
135
|
}
|
|
83
136
|
}
|
|
84
137
|
|
|
138
|
+
if (hasFiles) {
|
|
139
|
+
request += ', files=files';
|
|
140
|
+
}
|
|
141
|
+
|
|
85
142
|
if (headerCount > 0) {
|
|
86
143
|
request += ', headers=headers';
|
|
87
144
|
}
|
|
@@ -90,7 +147,12 @@ module.exports = function (source, options) {
|
|
|
90
147
|
|
|
91
148
|
code.push(request).blank().push('print(response.text)');
|
|
92
149
|
|
|
93
|
-
return
|
|
150
|
+
return (
|
|
151
|
+
code
|
|
152
|
+
.join()
|
|
153
|
+
// The `open()` call must be a literal in the code snippet.
|
|
154
|
+
.replace(/"open\('(.+)', 'rb'\)"/g, 'open("$1", "rb")')
|
|
155
|
+
);
|
|
94
156
|
};
|
|
95
157
|
|
|
96
158
|
module.exports.info = {
|
package/src/targets/r/httr.js
CHANGED
|
@@ -75,24 +75,20 @@ module.exports = function (source) {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
// Construct headers
|
|
78
|
-
const headers =
|
|
79
|
-
let headerCount = 0;
|
|
80
|
-
let header = '';
|
|
78
|
+
const headers = [];
|
|
81
79
|
let cookies;
|
|
82
80
|
let accept;
|
|
83
81
|
|
|
84
|
-
Object.keys(
|
|
85
|
-
if (
|
|
86
|
-
accept = `, accept("${
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
header += "', ";
|
|
95
|
-
}
|
|
82
|
+
Object.keys(source.allHeaders).forEach(header => {
|
|
83
|
+
if (header.toLowerCase() === 'accept') {
|
|
84
|
+
accept = `, accept("${source.allHeaders[header]}")`;
|
|
85
|
+
} else if (header.toLowerCase() === 'cookie') {
|
|
86
|
+
cookies = `, set_cookies(\`${source.allHeaders[header]
|
|
87
|
+
.replace(/;/g, '", `')
|
|
88
|
+
.replace(/` /g, '`')
|
|
89
|
+
.replace(/=/g, '` = "')}")`;
|
|
90
|
+
} else if (header.toLowerCase() !== 'content-type') {
|
|
91
|
+
headers.push(`'${header}' = '${source.allHeaders[header]}'`);
|
|
96
92
|
}
|
|
97
93
|
});
|
|
98
94
|
|
|
@@ -104,8 +100,8 @@ module.exports = function (source) {
|
|
|
104
100
|
request += ', body = payload';
|
|
105
101
|
}
|
|
106
102
|
|
|
107
|
-
if (
|
|
108
|
-
request += `, add_headers(${
|
|
103
|
+
if (headers.length) {
|
|
104
|
+
request += `, add_headers(${headers.join(', ')})`;
|
|
109
105
|
}
|
|
110
106
|
|
|
111
107
|
if (source.queryString.length) {
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @description
|
|
3
|
-
* HTTP code snippet generator for native Python3.
|
|
4
|
-
*
|
|
5
|
-
* @author
|
|
6
|
-
* @montanaflynn
|
|
7
|
-
*
|
|
8
|
-
* for any questions or issues regarding the generated code snippet, please open an issue mentioning the author.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
const CodeBuilder = require('../../helpers/code-builder');
|
|
12
|
-
|
|
13
|
-
module.exports = function (source) {
|
|
14
|
-
const code = new CodeBuilder();
|
|
15
|
-
// Start Request
|
|
16
|
-
code.push('import http.client').blank();
|
|
17
|
-
|
|
18
|
-
// Check which protocol to be used for the client connection
|
|
19
|
-
const protocol = source.uriObj.protocol;
|
|
20
|
-
if (protocol === 'https:') {
|
|
21
|
-
code.push('conn = http.client.HTTPSConnection("%s")', source.uriObj.host).blank();
|
|
22
|
-
} else {
|
|
23
|
-
code.push('conn = http.client.HTTPConnection("%s")', source.uriObj.host).blank();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Create payload string if it exists
|
|
27
|
-
const payload = JSON.stringify(source.postData.text);
|
|
28
|
-
if (payload) {
|
|
29
|
-
code.push('payload = %s', payload).blank();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Create Headers
|
|
33
|
-
const headers = source.allHeaders;
|
|
34
|
-
const headerCount = Object.keys(headers).length;
|
|
35
|
-
if (headerCount === 1) {
|
|
36
|
-
Object.keys(headers).forEach(header => {
|
|
37
|
-
code.push('headers = { \'%s\': "%s" }', header, headers[header]).blank();
|
|
38
|
-
});
|
|
39
|
-
} else if (headerCount > 1) {
|
|
40
|
-
let count = 1;
|
|
41
|
-
|
|
42
|
-
code.push('headers = {');
|
|
43
|
-
|
|
44
|
-
Object.keys(headers).forEach(header => {
|
|
45
|
-
// eslint-disable-next-line no-plusplus
|
|
46
|
-
if (count++ !== headerCount) {
|
|
47
|
-
code.push(' \'%s\': "%s",', header, headers[header]);
|
|
48
|
-
} else {
|
|
49
|
-
code.push(' \'%s\': "%s"', header, headers[header]);
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
code.push(' }').blank();
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Make Request
|
|
57
|
-
const method = source.method;
|
|
58
|
-
const path = source.uriObj.path;
|
|
59
|
-
if (payload && headerCount) {
|
|
60
|
-
code.push('conn.request("%s", "%s", payload, headers)', method, path);
|
|
61
|
-
} else if (payload && !headerCount) {
|
|
62
|
-
code.push('conn.request("%s", "%s", payload)', method, path);
|
|
63
|
-
} else if (!payload && headerCount) {
|
|
64
|
-
code.push('conn.request("%s", "%s", headers=headers)', method, path);
|
|
65
|
-
} else {
|
|
66
|
-
code.push('conn.request("%s", "%s")', method, path);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Get Response
|
|
70
|
-
code.blank().push('res = conn.getresponse()').push('data = res.read()').blank().push('print(data.decode("utf-8"))');
|
|
71
|
-
|
|
72
|
-
return code.join();
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
module.exports.info = {
|
|
76
|
-
key: 'python3',
|
|
77
|
-
title: 'http.client',
|
|
78
|
-
link: 'https://docs.python.org/3/library/http.client.html',
|
|
79
|
-
description: 'Python3 HTTP Client',
|
|
80
|
-
};
|