Skip to content

Commit c951cbe

Browse files
authored
Merge pull request #659 from postmanlabs/release/1.3.0
Release/1.3.0
2 parents d8f0ff6 + b452e3d commit c951cbe

File tree

28 files changed

+612
-194
lines changed

28 files changed

+612
-194
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
v1.3.0 (December 16, 2022)
2+
* Update C# restsharp codegen to support (107)[https://restsharp.dev/v107/]
3+
* Fixes an issue where HTTP code snippet was generating wrong boundaries (11084)[https://github.com/postmanlabs/postman-app-support/issues/11084]
4+
* Fixes an issue with Axios code snippets not including maxBodyLength param
5+
16
v1.2.1 (April 26, 2022)
27
* Add label for 'R' language
38

@@ -61,4 +66,4 @@ v1.0.1 (Jun 29, 2020)
6166
v1.0.0 (May 29, 2020)
6267
- Add axios framework support
6368
- Add ES6 syntax support for NodeJS Request, NodeJS Native and NodeJS Unirest
64-
- Fix snippet generation for powershell and jquery, where form data params had no type field
69+
- Fix snippet generation for powershell and jquery, where form data params had no type field

codegens/csharp-restsharp/lib/parseRequest.js

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,49 @@ function parseContentType (request) {
4141
return request.getHeaders({enabled: true, ignoreCase: true})['content-type'] || 'text/plain';
4242
}
4343

44+
/**
45+
* Generates a parameter using AddStringBody method
46+
*
47+
* @param {Object} requestBody - JSON object representing body of request
48+
* @param {string} dataFormat - the data format to use "DataFormat.Json" or "DataFormat.Xml"
49+
* @returns {String} snippet of the parameter generation
50+
*/
51+
function getAddStringBodyParam (requestBody, dataFormat) {
52+
return `var body = ${requestBody[requestBody.mode]
53+
.split('\n')
54+
.map((line) => { return '@"' + line.replace(/"/g, '""') + '"'; })
55+
.join(' + "\\n" +\n')};\n` +
56+
`request.AddStringBody(body, ${dataFormat});\n`;
57+
}
58+
59+
/**
60+
* Parses Raw data
61+
*
62+
* @param {Object} request - JSON object representing body of request
63+
* @param {Object} requestBody - JSON object representing body of request
64+
* @returns {String} snippet of the body generation
65+
*/
66+
function parseRawBody (request, requestBody) {
67+
let bodySnippet = '',
68+
contentType = parseContentType(request);
69+
if (contentType && (contentType === 'application/json' || contentType.match(/\+json$/))) {
70+
bodySnippet = getAddStringBodyParam(requestBody, 'DataFormat.Json');
71+
}
72+
else if (contentType && (contentType === 'text/xml' || contentType.match(/\+xml$/))) {
73+
bodySnippet = getAddStringBodyParam(requestBody, 'DataFormat.Xml');
74+
}
75+
else {
76+
bodySnippet = `var body = ${requestBody[requestBody.mode]
77+
.split('\n')
78+
.map((line) => { return '@"' + line.replace(/"/g, '""') + '"'; })
79+
.join(' + "\\n" +\n')};\n` +
80+
`request.AddParameter("${contentType}", ` +
81+
'body, ParameterType.RequestBody);\n';
82+
}
83+
84+
return bodySnippet;
85+
}
86+
4487
/**
4588
*
4689
* @param {Object} requestBody - JSON object representing body of request
@@ -78,12 +121,7 @@ function parseBody (request, trimFields) {
78121
case 'formdata':
79122
return parseFormData(requestBody, trimFields);
80123
case 'raw':
81-
return `var body = ${requestBody[requestBody.mode]
82-
.split('\n')
83-
.map((line) => { return '@"' + line.replace(/"/g, '""') + '"'; })
84-
.join(' + "\\n" +\n')};\n` +
85-
`request.AddParameter("${parseContentType(request)}", ` +
86-
'body, ParameterType.RequestBody);\n';
124+
return parseRawBody(request, requestBody);
87125
case 'graphql':
88126
return parseGraphQL(requestBody, trimFields);
89127
/* istanbul ignore next */
@@ -110,10 +148,7 @@ function parseHeader (requestJson) {
110148

111149
return requestJson.header.reduce((headerSnippet, header) => {
112150
if (!header.disabled) {
113-
if (sanitize(header.key, true).toLowerCase() === 'user-agent') {
114-
headerSnippet += `client.UserAgent = "${sanitize(header.value)}";\n`;
115-
}
116-
else {
151+
if (sanitize(header.key, true).toLowerCase() !== 'user-agent') {
117152
headerSnippet += `request.AddHeader("${sanitize(header.key, true)}", "${sanitize(header.value)}");\n`;
118153
}
119154
}

codegens/csharp-restsharp/lib/restsharp.js

Lines changed: 99 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,100 @@ var _ = require('./lodash'),
44
sanitize = require('./util').sanitize,
55
sanitizeOptions = require('./util').sanitizeOptions,
66
addFormParam = require('./util').addFormParam,
7+
{ URL } = require('url'),
78
self;
89

910
/**
10-
* Generates snippet in csharp-restsharp by parsing data from Postman-SDK request object
11+
* Takes in a string and returns a new string with only the first character capitalized
12+
*
13+
* @param {string} string - string to change
14+
* @returns {String} - the same string with the first litter as capital letter
15+
*/
16+
function capitalizeFirstLetter (string) {
17+
return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
18+
}
19+
20+
/**
21+
* Generates snippet for the RestClientOptions object
1122
*
12-
* @param {Object} request - Postman SDK request object
23+
* @param {string} urlOrigin - String representing the origin of the url
1324
* @param {Object} options - Options to tweak code snippet
14-
* @returns {String} csharp-restsharp code snippet for given request object
25+
* @param {string} indentString - String representing value of indentation required
26+
* @param {Array} headers - request headers
27+
* @returns {String} csharp-restsharp RestClientOptions object snippet
1528
*/
16-
function makeSnippet (request, options) {
17-
const UNSUPPORTED_METHODS_LIKE_POST = ['LINK', 'UNLINK', 'LOCK', 'PROPFIND'],
18-
UNSUPPORTED_METHODS_LIKE_GET = ['PURGE', 'UNLOCK', 'VIEW', 'COPY'];
29+
function makeOptionsSnippet (urlOrigin, options, indentString, headers) {
30+
let userAgentHeader,
31+
snippet = `var options = new RestClientOptions("${sanitize(urlOrigin)}")\n{\n`;
32+
if (Array.isArray(headers)) {
33+
userAgentHeader = headers.find((header) => {
34+
return (!header.disabled && sanitize(header.key, true).toLowerCase() === 'user-agent');
1935

20-
var snippet = `var client = new RestClient("${sanitize(request.url.toString())}");\n`,
21-
isUnSupportedMethod = UNSUPPORTED_METHODS_LIKE_GET.includes(request.method) ||
22-
UNSUPPORTED_METHODS_LIKE_POST.includes(request.method);
36+
});
37+
}
2338
if (options.requestTimeout) {
24-
snippet += `client.Timeout = ${options.requestTimeout};\n`;
39+
snippet += `${indentString}MaxTimeout = ${options.requestTimeout},\n`;
2540
}
2641
else {
27-
snippet += 'client.Timeout = -1;\n';
42+
snippet += `${indentString}MaxTimeout = -1,\n`;
2843
}
2944
if (!options.followRedirect) {
30-
snippet += 'client.FollowRedirects = false;\n';
45+
snippet += `${indentString}FollowRedirects = false,\n`;
46+
}
47+
if (userAgentHeader) {
48+
snippet += `${indentString}UserAgent = "${userAgentHeader.value}",\n`;
49+
}
50+
snippet += '};\n';
51+
return snippet;
52+
}
53+
54+
/**
55+
* Generates an URL object from the string
56+
*
57+
* @param {string} stringToParse - url in string representation
58+
* @returns {object} the URL object
59+
*/
60+
function parseURL (stringToParse) {
61+
try {
62+
let objectURL = new URL(stringToParse);
63+
return objectURL;
64+
}
65+
catch (err) {
66+
try {
67+
var url = require('url');
68+
let urlObj = url.parse(stringToParse);
69+
if (urlObj.hostname === null) {
70+
return false;
71+
}
72+
return urlObj;
73+
}
74+
catch (parseErr) {
75+
return false;
76+
}
3177
}
32-
snippet += `var request = new RestRequest(${isUnSupportedMethod ? '' : ('Method.' + request.method)});\n`;
78+
}
79+
80+
/**
81+
* Generates snippet in csharp-restsharp by parsing data from Postman-SDK request object
82+
*
83+
* @param {Object} request - Postman SDK request object
84+
* @param {Object} options - Options to tweak code snippet
85+
* @param {string} indentString - String representing value of indentation required
86+
* @returns {string} csharp-restsharp code snippet for given request object
87+
*/
88+
function makeSnippet (request, options, indentString) {
89+
const UNSUPPORTED_METHODS_LIKE_POST = ['LINK', 'UNLINK', 'LOCK', 'PROPFIND'],
90+
UNSUPPORTED_METHODS_LIKE_GET = ['PURGE', 'UNLOCK', 'VIEW'],
91+
isUnSupportedMethod = UNSUPPORTED_METHODS_LIKE_GET.includes(request.method) ||
92+
UNSUPPORTED_METHODS_LIKE_POST.includes(request.method),
93+
url = parseURL(request.url.toString()),
94+
urlOrigin = url ? parseURL(request.url.toString()).origin : request.url.toString(),
95+
urlPathAndHash = url ? request.url.toString().replace(urlOrigin, '') : '';
96+
97+
let snippet = makeOptionsSnippet(urlOrigin, options, indentString, request.toJSON().header);
98+
snippet += 'var client = new RestClient(options);\n';
99+
snippet += `var request = new RestRequest("${sanitize(urlPathAndHash)}", ` +
100+
`${isUnSupportedMethod ? 'Method.Get' : ('Method.' + capitalizeFirstLetter(request.method))});\n`;
33101
if (request.body && request.body.mode === 'graphql' && !request.headers.has('Content-Type')) {
34102
request.addHeader({
35103
key: 'Content-Type',
@@ -38,17 +106,11 @@ function makeSnippet (request, options) {
38106
}
39107
snippet += parseRequest.parseHeader(request.toJSON(), options.trimRequestBody);
40108
if (request.body && request.body.mode === 'formdata') {
41-
let isFile = false,
42-
formdata = request.body.formdata,
109+
let formdata = request.body.formdata,
43110
formdataArray = [];
44-
request.body.toJSON().formdata.forEach((data) => {
45-
if (!data.disabled && data.type === 'file') {
46-
isFile = true;
47-
}
48-
});
49111
// The following statement needs to be added else the multipart/form-data request where there is no file
50112
// is being sent as x-www-form-urlencoded by default
51-
if (!isFile) {
113+
if (formdata.members.length > 0) {
52114
snippet += 'request.AlwaysMultipartFormData = true;\n';
53115
}
54116

@@ -92,14 +154,14 @@ function makeSnippet (request, options) {
92154
}
93155
snippet += parseRequest.parseBody(request, options.trimRequestBody);
94156
if (isUnSupportedMethod) {
95-
(UNSUPPORTED_METHODS_LIKE_GET.includes(request.method)) &&
96-
(snippet += `IRestResponse response = client.ExecuteAsGet(request, "${request.method}");\n`);
97-
(UNSUPPORTED_METHODS_LIKE_POST.includes(request.method)) &&
98-
(snippet += `IRestResponse response = client.ExecuteAsPost(request, "${request.method}");\n`);
99-
}
100-
else {
101-
snippet += 'IRestResponse response = client.Execute(request);\n';
157+
snippet += 'request.OnBeforeRequest = (request) =>\n';
158+
snippet += '{\n';
159+
snippet += `${indentString}request.Method = new HttpMethod("${request.method}");\n`;
160+
snippet += `${indentString}return default;\n`;
161+
snippet += '};\n';
102162
}
163+
164+
snippet += 'RestResponse response = await client.ExecuteAsync(request);\n';
103165
snippet += 'Console.WriteLine(response.Content);';
104166

105167
return snippet;
@@ -192,7 +254,8 @@ self = module.exports = {
192254
// snippets to include C# class definition according to options
193255
headerSnippet = '',
194256
footerSnippet = '',
195-
257+
mainMethodSnippet = '',
258+
importTask = '',
196259
// snippet to create request in csharp-restsharp
197260
snippet = '';
198261

@@ -202,15 +265,20 @@ self = module.exports = {
202265
indentString = indentString.repeat(options.indentCount);
203266

204267
if (options.includeBoilerplate) {
268+
269+
mainMethodSnippet = indentString.repeat(2) + 'static async Task Main(string[] args) {\n';
270+
importTask = 'using System.Threading;\nusing System.Threading.Tasks;\n';
271+
205272
headerSnippet = 'using System;\n' +
206273
'using RestSharp;\n' +
274+
importTask +
207275
'namespace HelloWorldApplication {\n' +
208276
indentString + 'class HelloWorld {\n' +
209-
indentString.repeat(2) + 'static void Main(string[] args) {\n';
277+
mainMethodSnippet;
210278
footerSnippet = indentString.repeat(2) + '}\n' + indentString + '}\n}\n';
211279
}
212280

213-
snippet = makeSnippet(request, options);
281+
snippet = makeSnippet(request, options, indentString);
214282

215283
// if boilerplate is included then two more indentString needs to be added in snippet
216284
(options.includeBoilerplate) &&

codegens/csharp-restsharp/test/unit/convert.test.js

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ var expect = require('chai').expect,
44
mainCollection = require('./fixtures/testcollection/collection.json'),
55
testCollection = require('./fixtures/testcollection/collectionForEdge.json'),
66
getOptions = require('../../lib/index').getOptions,
7-
testResponse = require('./fixtures/testresponse.json'),
7+
testResponseAsync = require('./fixtures/testResponseAsync.json'),
8+
testResponseJsonParams = require('./fixtures/testResponseJsonParams.json'),
89
sanitize = require('../../lib/util').sanitize,
910
sanitizeOptions = require('../../lib/util').sanitizeOptions;
1011

1112
describe('csharp restsharp function', function () {
1213

1314
describe('csharp-restsharp convert function', function () {
14-
it('should return expected snippet', function () {
15+
it('should return expected snippet - Async', function () {
1516
var request = new sdk.Request(mainCollection.item[4].request),
1617
options = {
1718
indentCount: 1,
@@ -25,7 +26,25 @@ describe('csharp restsharp function', function () {
2526
expect.fail(null, null, error);
2627
return;
2728
}
28-
expect(snippet).deep.equal(testResponse.result);
29+
expect(snippet).deep.equal(testResponseAsync.result);
30+
});
31+
});
32+
33+
it('should return expected snippet json params', function () {
34+
var request = new sdk.Request(mainCollection.item[5].request),
35+
options = {
36+
indentCount: 1,
37+
indentType: 'Tab',
38+
followRedirect: true,
39+
trimRequestBody: true
40+
};
41+
42+
convert(request, options, function (error, snippet) {
43+
if (error) {
44+
expect.fail(null, null, error);
45+
return;
46+
}
47+
expect(snippet).deep.equal(testResponseJsonParams.result);
2948
});
3049
});
3150
});
@@ -45,7 +64,9 @@ describe('csharp restsharp function', function () {
4564
expect.fail(null, null, error);
4665
return;
4766
}
48-
expect(snippet).to.include('using System;\nusing RestSharp;\nnamespace HelloWorldApplication {\n');
67+
expect(snippet).to.include('using System;\nusing RestSharp;\nusing System.Threading;\nusing' +
68+
' System.Threading.Tasks;\nnamespace HelloWorldApplication {\n');
69+
expect(snippet).to.include('static async Task Main(string[] args) {');
4970
});
5071
});
5172

@@ -72,7 +93,7 @@ describe('csharp restsharp function', function () {
7293
expect.fail(null, null, error);
7394
}
7495
expect(snippet).to.be.a('string');
75-
expect(snippet).to.include('client.Timeout = 5');
96+
expect(snippet).to.include('MaxTimeout = 5');
7697
});
7798
});
7899

@@ -82,7 +103,7 @@ describe('csharp restsharp function', function () {
82103
expect.fail(null, null, error);
83104
}
84105
expect(snippet).to.be.a('string');
85-
expect(snippet).to.include('client.FollowRedirects = false');
106+
expect(snippet).to.include('FollowRedirects = false');
86107
});
87108
});
88109

@@ -165,7 +186,7 @@ describe('csharp restsharp function', function () {
165186

166187
it('should use client.UserAgent instead of AddHeader function', function () {
167188
const sampleUA = 'Safari/605.1.15',
168-
expectValue = `client.UserAgent = "${sampleUA}";`;
189+
expectValue = `UserAgent = "${sampleUA}",`;
169190

170191
var request = new sdk.Request({
171192
'method': 'GET',
@@ -192,6 +213,7 @@ describe('csharp restsharp function', function () {
192213
expect(snippet).to.include(expectValue);
193214
});
194215
});
216+
195217
});
196218

197219
describe('getOptions function', function () {
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"result" : "var options = new RestClientOptions(\"https://postman-echo.com\")\n{\n\tMaxTimeout = -1,\n};\nvar client = new RestClient(options);\nvar request = new RestRequest(\"/post/?hardik=\\\"me\\\"\", Method.Post);\nrequest.AddHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\nrequest.AddParameter(\"1\", \"a\");\nrequest.AddParameter(\"2\", \"b\");\nrequest.AddParameter(\"\\\"\\\"12\\\"\\\"\", \"\\\"23\\\"\");\nrequest.AddParameter(\"'1\\\"2\\\\\\\"\\\"3'\", \"'1\\\"23\\\"4'\");\nRestResponse response = await client.ExecuteAsync(request);\nConsole.WriteLine(response.Content);"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"result": "var options = new RestClientOptions(\"https://postman-echo.com\")\n{\n\tMaxTimeout = -1,\n};\nvar client = new RestClient(options);\nvar request = new RestRequest(\"/post\", Method.Post);\nrequest.AddHeader(\"Content-Type\", \"application/json\");\nvar body = @\"{\" + \"\\n\" +\n@\" \"\"json\"\": \"\"Test-Test\"\"\" + \"\\n\" +\n@\"}\";\nrequest.AddStringBody(body, DataFormat.Json);\nRestResponse response = await client.ExecuteAsync(request);\nConsole.WriteLine(response.Content);"
3+
}

codegens/csharp-restsharp/test/unit/fixtures/testresponse.json

Lines changed: 0 additions & 3 deletions
This file was deleted.

codegens/dart-http/test/newman/newman.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ describe('Convert for different types of request', function () {
99
headerSnippet: '',
1010
// http uses Map<String, String> to store headers, so there is no way to
1111
// keep multiple headers with the same key
12-
skipCollections: ['sameNameHeadersCollection']
12+
skipCollections: ['sameNameHeadersCollection', 'unsupportedMethods']
1313
};
1414

1515
runNewmanTest(convert, options, testConfig);

0 commit comments

Comments
 (0)