feat(http): simplify URLSearchParams creation (#13338)

Closes #8858
This commit is contained in:
Dzmitry Shylovich 2016-12-10 02:38:29 +03:00 committed by Victor Berchet
parent aaf6e05f56
commit 90c223591f
5 changed files with 85 additions and 17 deletions

View File

@ -62,7 +62,15 @@ export class RequestOptions {
/** /**
* Search parameters to be included in a {@link Request}. * Search parameters to be included in a {@link Request}.
*/ */
search: URLSearchParams; params: URLSearchParams;
/**
* @deprecated from 4.0.0. Use params instead.
*/
get search(): URLSearchParams { return this.params; }
/**
* @deprecated from 4.0.0. Use params instead.
*/
set search(params: URLSearchParams) { this.params = params; }
/** /**
* Enable use credentials for a {@link Request}. * Enable use credentials for a {@link Request}.
*/ */
@ -72,15 +80,15 @@ export class RequestOptions {
*/ */
responseType: ResponseContentType; responseType: ResponseContentType;
// TODO(Dzmitry): remove search when this.search is removed
constructor( constructor(
{method, headers, body, url, search, withCredentials, {method, headers, body, url, search, params, withCredentials,
responseType}: RequestOptionsArgs = {}) { responseType}: RequestOptionsArgs = {}) {
this.method = method != null ? normalizeMethodName(method) : null; this.method = method != null ? normalizeMethodName(method) : null;
this.headers = headers != null ? headers : null; this.headers = headers != null ? headers : null;
this.body = body != null ? body : null; this.body = body != null ? body : null;
this.url = url != null ? url : null; this.url = url != null ? url : null;
this.search = this.params = this._mergeSearchParams(params || search);
search != null ? (typeof search === 'string' ? new URLSearchParams(search) : search) : null;
this.withCredentials = withCredentials != null ? withCredentials : null; this.withCredentials = withCredentials != null ? withCredentials : null;
this.responseType = responseType != null ? responseType : null; this.responseType = responseType != null ? responseType : null;
} }
@ -116,18 +124,49 @@ export class RequestOptions {
headers: options && options.headers != null ? options.headers : this.headers, headers: options && options.headers != null ? options.headers : this.headers,
body: options && options.body != null ? options.body : this.body, body: options && options.body != null ? options.body : this.body,
url: options && options.url != null ? options.url : this.url, url: options && options.url != null ? options.url : this.url,
search: options && options.search != null ? params: options && this._mergeSearchParams(options.params || options.search),
(typeof options.search === 'string' ? new URLSearchParams(options.search) :
options.search.clone()) :
this.search,
withCredentials: options && options.withCredentials != null ? options.withCredentials : withCredentials: options && options.withCredentials != null ? options.withCredentials :
this.withCredentials, this.withCredentials,
responseType: options && options.responseType != null ? options.responseType : responseType: options && options.responseType != null ? options.responseType :
this.responseType this.responseType
}); });
} }
}
private _mergeSearchParams(params: string|URLSearchParams|
{[key: string]: any | any[]}): URLSearchParams {
if (!params) return this.params;
if (params instanceof URLSearchParams) {
return params.clone();
}
if (typeof params === 'string') {
return new URLSearchParams(params);
}
return this._parseParams(params);
}
private _parseParams(objParams: {[key: string]: any | any[]} = {}): URLSearchParams {
const params = new URLSearchParams();
Object.keys(objParams).forEach((key: string) => {
const value: any|any[] = objParams[key];
if (Array.isArray(value)) {
value.forEach((item: any) => this._appendParam(key, item, params));
} else {
this._appendParam(key, value, params);
}
});
return params;
}
private _appendParam(key: string, value: any, params: URLSearchParams): void {
if (typeof value !== 'string') {
value = JSON.stringify(value);
}
params.append(key, value);
}
}
/** /**
* Subclass of {@link RequestOptions}, with default values. * Subclass of {@link RequestOptions}, with default values.

View File

@ -48,7 +48,9 @@ export abstract class XSRFStrategy { abstract configureRequest(req: Request): vo
export interface RequestOptionsArgs { export interface RequestOptionsArgs {
url?: string; url?: string;
method?: string|RequestMethod; method?: string|RequestMethod;
search?: string|URLSearchParams; /** @deprecated from 4.0.0. Use params instead. */
search?: string|URLSearchParams|{[key: string]: any | any[]};
params?: string|URLSearchParams|{[key: string]: any | any[]};
headers?: Headers; headers?: Headers;
body?: any; body?: any;
withCredentials?: boolean; withCredentials?: boolean;

View File

@ -76,15 +76,15 @@ export class Request extends Body {
// TODO: assert that url is present // TODO: assert that url is present
const url = requestOptions.url; const url = requestOptions.url;
this.url = requestOptions.url; this.url = requestOptions.url;
if (requestOptions.search) { if (requestOptions.params) {
const search = requestOptions.search.toString(); const params = requestOptions.params.toString();
if (search.length > 0) { if (params.length > 0) {
let prefix = '?'; let prefix = '?';
if (this.url.indexOf('?') != -1) { if (this.url.indexOf('?') != -1) {
prefix = (this.url[this.url.length - 1] == '&') ? '' : '&'; prefix = (this.url[this.url.length - 1] == '&') ? '' : '&';
} }
// TODO: just delete search-query-looking string in url? // TODO: just delete search-query-looking string in url?
this.url = url + prefix + search; this.url = url + prefix + params;
} }
} }
this._body = requestOptions.body; this._body = requestOptions.body;

View File

@ -24,5 +24,26 @@ export function main() {
const options2 = options1.merge(new RequestOptions({method: RequestMethod.Delete})); const options2 = options1.merge(new RequestOptions({method: RequestMethod.Delete}));
expect(options2.method).toBe(RequestMethod.Delete); expect(options2.method).toBe(RequestMethod.Delete);
}); });
it('should accept search params as object', () => {
const params = {a: 1, b: 'text', c: [1, 2, '3']};
const options = new RequestOptions({params});
expect(options.params.paramsMap.size).toBe(3);
expect(options.params.paramsMap.get('a')).toEqual(['1']);
expect(options.params.paramsMap.get('b')).toEqual(['text']);
expect(options.params.paramsMap.get('c')).toEqual(['1', '2', '3']);
});
it('should merge search params as object', () => {
const options1 = new BaseRequestOptions();
const params = {a: 1, b: 'text', c: [1, 2, '3']};
const options2 = options1.merge(new RequestOptions({params}));
expect(options2.params.paramsMap.size).toBe(3);
expect(options2.params.paramsMap.get('a')).toEqual(['1']);
expect(options2.params.paramsMap.get('b')).toEqual(['text']);
expect(options2.params.paramsMap.get('c')).toEqual(['1', '2', '3']);
});
}); });
} }

View File

@ -139,11 +139,12 @@ export declare class RequestOptions {
body: any; body: any;
headers: Headers; headers: Headers;
method: RequestMethod | string; method: RequestMethod | string;
params: URLSearchParams;
responseType: ResponseContentType; responseType: ResponseContentType;
search: URLSearchParams; /** @deprecated */ search: URLSearchParams;
url: string; url: string;
withCredentials: boolean; withCredentials: boolean;
constructor({method, headers, body, url, search, withCredentials, responseType}?: RequestOptionsArgs); constructor({method, headers, body, url, search, params, withCredentials, responseType}?: RequestOptionsArgs);
merge(options?: RequestOptionsArgs): RequestOptions; merge(options?: RequestOptionsArgs): RequestOptions;
} }
@ -152,8 +153,13 @@ export interface RequestOptionsArgs {
body?: any; body?: any;
headers?: Headers; headers?: Headers;
method?: string | RequestMethod; method?: string | RequestMethod;
params?: string | URLSearchParams | {
[key: string]: any | any[];
};
responseType?: ResponseContentType; responseType?: ResponseContentType;
search?: string | URLSearchParams; /** @deprecated */ search?: string | URLSearchParams | {
[key: string]: any | any[];
};
url?: string; url?: string;
withCredentials?: boolean; withCredentials?: boolean;
} }