Skip to content

Commit ab5bc50

Browse files
author
damccorm
authored
Fixing conversion from nested objects to url (#226)
* Fixing serialization * Missed file, still fixing serialization * Removing js file added on accident * Responding to feedback * Responding to feedback
1 parent 7b66ae5 commit ab5bc50

File tree

3 files changed

+48
-41
lines changed

3 files changed

+48
-41
lines changed

api/VsoClient.ts

+25-39
Original file line numberDiff line numberDiff line change
@@ -183,41 +183,37 @@ export class VsoClient {
183183
return url.resolve(this.baseUrl, path.join(this.basePath, relativeUrl));
184184
}
185185

186-
private getSerializedObject(queryValue: any, object: any): string {
187-
let value:string = "";
188-
let first:boolean = true;
189-
190-
for (let property in object) {
191-
if (object.hasOwnProperty(property)) {
192-
let prop = object[property];
193-
let valueString = this.getValueString(property, prop);
194-
if (first && prop !== undefined) {
195-
value += valueString;
196-
first = false;
197-
} else if (prop !== undefined) {
198-
value += "&" + valueString;
186+
private queryParamsToStringHelper(queryParams: any, prefix: string): string {
187+
if (queryParams === undefined) {
188+
return '';
189+
}
190+
let queryString: string = '';
191+
192+
if(typeof(queryParams) !== 'string') {
193+
for (let property in queryParams) {
194+
if (queryParams.hasOwnProperty(property)) {
195+
const prop = queryParams[property];
196+
const newPrefix = prefix + encodeURIComponent(property.toString()) + '.';
197+
queryString += this.queryParamsToStringHelper(prop, newPrefix);
199198
}
200199
}
201200
}
202201

203-
if (value == ""){
204-
value += queryValue + "=" + object.toString();
202+
if(queryString === '' && prefix.length > 0){
203+
// Will always need to chop period off of end of prefix
204+
queryString = prefix.slice(0,-1) + '=' + encodeURIComponent(queryParams.toString()) + '&';
205205
}
206-
return value;
206+
return queryString;
207207
}
208208

209-
private getValueString(queryValue, value) {
210-
let valueString = null;
211-
if (typeof(value) === 'object') {
212-
valueString = this.getSerializedObject(queryValue, value);
213-
} else {
214-
valueString = queryValue + "=" + encodeURIComponent(value);
215-
}
216-
return valueString;
209+
private queryParamsToString(queryParams: any): string {
210+
const queryString: string = '?' + this.queryParamsToStringHelper(queryParams, '');
211+
212+
// Will always need to slice either a ? or & off of the end
213+
return queryString.slice(0,-1);
217214
}
218215

219216
protected getRequestUrl(routeTemplate: string, area: string, resource: string, routeValues: any, queryParams?: any): string {
220-
221217
// Add area/resource route values (based on the location)
222218
routeValues = routeValues || {};
223219
if (!routeValues.area) {
@@ -230,22 +226,12 @@ export class VsoClient {
230226
// Replace templated route values
231227
let relativeUrl = this.replaceRouteValues(routeTemplate, routeValues);
232228

233-
//append query parameters to the end
234-
let first = true;
235-
for (let queryValue in queryParams) {
236-
if (queryParams[queryValue] != null) {
237-
let value = queryParams[queryValue];
238-
let valueString = this.getValueString(queryValue, value);
239-
if (first) {
240-
relativeUrl += "?" + valueString;
241-
first = false;
242-
} else {
243-
relativeUrl += "&" + valueString;
244-
}
245-
}
229+
// Append query parameters to the end
230+
if (queryParams) {
231+
relativeUrl += this.queryParamsToString(queryParams);
246232
}
247233

248-
//resolve the relative url with the base
234+
// Resolve the relative url with the base
249235
return url.resolve(this.baseUrl, path.join(this.basePath, relativeUrl));
250236
}
251237

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "azure-devops-node-api",
33
"description": "Node client for Azure DevOps and TFS REST APIs",
4-
"version": "6.6.1",
4+
"version": "6.6.2",
55
"main": "./WebApi.js",
66
"types": "./WebApi.d.ts",
77
"scripts": {

test/units/tests.ts

+22-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,28 @@ describe('VSOClient Units', function () {
138138

139139
//Assert
140140
assert(res.apiVersion === '1');
141-
assert(res.requestUrl === 'https://dev.azure.com/testTemplate?innerstatus=2');
141+
assert(res.requestUrl === 'https://dev.azure.com/testTemplate?status.innerstatus=2');
142+
});
143+
144+
it('gets versioning data with complex nested query params', async () => {
145+
//Arrange
146+
nock('https://dev.azure.com/_apis/testArea5', {
147+
reqheaders: {
148+
'accept': 'application/json',
149+
'user-agent': 'testAgent'
150+
}})
151+
.options('')
152+
.reply(200, {
153+
value: [{id: 'testLocation', maxVersion: '1', releasedVersion: '1', routeTemplate: 'testTemplate', area: 'testArea5', resourceName: 'testName', resourceVersion: '1'}]
154+
});
155+
156+
//Act
157+
const queryParams = {status: {innerstatus: 2}, version: '1', nestedObject: {nestedField: 'value', innerNestedObject: {key: 'val2'}}};
158+
const res: vsom.ClientVersioningData = await vsoClient.getVersioningData('1', 'testArea5', 'testLocation', {'testKey': 'testValue'}, queryParams);
159+
160+
//Assert
161+
assert.equal(res.apiVersion, '1');
162+
assert.equal(res.requestUrl, 'https://dev.azure.com/testTemplate?status.innerstatus=2&version=1&nestedObject.nestedField=value&nestedObject.innerNestedObject.key=val2');
142163
});
143164

144165
it('gets versioning data after an initialization promise', async () => {

0 commit comments

Comments
 (0)