async ajax()

in packages/api-rest/src/RestClient.ts [91:226]


	async ajax(urlOrApiInfo: string | ApiInfo, method: string, init) {
		logger.debug(method, urlOrApiInfo);

		let parsed_url;
		let url: string;
		let region: string = 'us-east-1';
		let service: string = 'execute-api';
		let custom_header: () => {
			[key: string]: string;
		} = undefined;

		if (typeof urlOrApiInfo === 'string') {
			parsed_url = this._parseUrl(urlOrApiInfo);
			url = urlOrApiInfo;
		} else {
			({ endpoint: url, custom_header, region, service } = urlOrApiInfo);
			parsed_url = this._parseUrl(urlOrApiInfo.endpoint);
		}

		const params = {
			method,
			url,
			host: parsed_url.host,
			path: parsed_url.path,
			headers: {},
			data: null,
			responseType: 'json',
			timeout: 0,
			cancelToken: null,
		};

		let libraryHeaders = {};

		if (Platform.isReactNative) {
			const userAgent = Platform.userAgent || 'aws-amplify/0.1.x';
			libraryHeaders = {
				'User-Agent': userAgent,
			};
		}

		const initParams = Object.assign({}, init);
		const isAllResponse = initParams.response;
		if (initParams.body) {
			if (
				typeof FormData === 'function' &&
				initParams.body instanceof FormData
			) {
				libraryHeaders['Content-Type'] = 'multipart/form-data';
				params.data = initParams.body;
			} else {
				libraryHeaders['Content-Type'] = 'application/json; charset=UTF-8';
				params.data = JSON.stringify(initParams.body);
			}
		}
		if (initParams.responseType) {
			params.responseType = initParams.responseType;
		}
		if (initParams.withCredentials) {
			params['withCredentials'] = initParams.withCredentials;
		}
		if (initParams.timeout) {
			params.timeout = initParams.timeout;
		}
		if (initParams.cancellableToken) {
			params.cancelToken = initParams.cancellableToken.token;
		}

		params['signerServiceInfo'] = initParams.signerServiceInfo;

		// custom_header callback
		const custom_header_obj =
			typeof custom_header === 'function' ? await custom_header() : undefined;

		params.headers = {
			...libraryHeaders,
			...custom_header_obj,
			...initParams.headers,
		};

		// Intentionally discarding search
		const { search, ...parsedUrl } = parse(url, true, true);
		params.url = format({
			...parsedUrl,
			query: {
				...parsedUrl.query,
				...(initParams.queryStringParameters || {}),
			},
		});

		// Do not sign the request if client has added 'Authorization' header,
		// which means custom authorizer.
		if (typeof params.headers['Authorization'] !== 'undefined') {
			params.headers = Object.keys(params.headers).reduce((acc, k) => {
				if (params.headers[k]) {
					acc[k] = params.headers[k];
				}
				return acc;
				// tslint:disable-next-line:align
			}, {});
			return this._request(params, isAllResponse);
		}

		// Signing the request in case there credentials are available
		return this.Credentials.get().then(
			credentials => {
				return this._signed({ ...params }, credentials, isAllResponse, {
					region,
					service,
				}).catch(error => {
					if (DateUtils.isClockSkewError(error)) {
						const { headers } = error.response;
						const dateHeader = headers && (headers.date || headers.Date);
						const responseDate = new Date(dateHeader);
						const requestDate = DateUtils.getDateFromHeaderString(
							params.headers['x-amz-date']
						);

						// Compare local clock to the server clock
						if (DateUtils.isClockSkewed(responseDate)) {
							DateUtils.setClockOffset(
								responseDate.getTime() - requestDate.getTime()
							);

							return this.ajax(urlOrApiInfo, method, init);
						}
					}

					throw error;
				});
			},
			err => {
				logger.debug('No credentials available, the request will be unsigned');
				return this._request(params, isAllResponse);
			}
		);
	}