Skip to content

Commit

Permalink
Convert Resource request methods to use promises
Browse files Browse the repository at this point in the history
The `throwError` parameter here is to handle the fact that, when using
an HttpPaginatedResponse, PaginatedResource wishes to have access to
both the error that comes from the HTTP client _and_ the response body,
before deciding how to handle an error (see the `returnErrOnly`
function).

I’ve converted Resource.do to return a promise here, but I’ll do the
full conversion of that method in a separate commit for readability’s
sake.
  • Loading branch information
lawrence-forooghian committed Jan 11, 2024
1 parent 44d0353 commit 033501d
Show file tree
Hide file tree
Showing 6 changed files with 298 additions and 277 deletions.
118 changes: 28 additions & 90 deletions src/common/lib/client/paginatedresource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as Utils from '../util/utils';
import Logger from '../util/logger';
import Resource from './resource';
import Resource, { ResourceResult } from './resource';
import { IPartialErrorInfo } from '../types/errorinfo';
import BaseClient from './baseclient';
import { RequestCallbackHeaders } from 'common/types/http';
Expand Down Expand Up @@ -59,115 +59,63 @@ class PaginatedResource {
}

async get<T1, T2>(params: Record<string, T2>): Promise<PaginatedResult<T1>> {
return new Promise((resolve) => {
Resource.get(
this.client,
this.path,
this.headers,
params,
this.envelope,
(err, body, headers, unpacked, statusCode) => {
resolve(this.handlePage(err, body, headers, unpacked, statusCode));
}
);
});
const result = await Resource.get<T1>(this.client, this.path, this.headers, params, this.envelope, false);
return this.handlePage(result);
}

async delete<T1, T2>(params: Record<string, T2>): Promise<PaginatedResult<T1>> {
return new Promise((resolve) => {
Resource.delete(
this.client,
this.path,
this.headers,
params,
this.envelope,
(err, body, headers, unpacked, statusCode) => {
resolve(this.handlePage(err, body, headers, unpacked, statusCode));
}
);
});
const result = await Resource.delete<T1>(this.client, this.path, this.headers, params, this.envelope, false);
return this.handlePage(result);
}

async post<T1, T2>(params: Record<string, T2>, body: unknown): Promise<PaginatedResult<T1>> {
return new Promise((resolve) => {
Resource.post(
this.client,
this.path,
body,
this.headers,
params,
this.envelope,
(err, responseBody, headers, unpacked, statusCode) => {
resolve(this.handlePage(err, responseBody, headers, unpacked, statusCode));
}
);
});
const result = await Resource.post<T1>(this.client, this.path, body, this.headers, params, this.envelope, false);
return this.handlePage(result);
}

async put<T1, T2>(params: Record<string, T2>, body: unknown): Promise<PaginatedResult<T1>> {
return new Promise((resolve) => {
Resource.put(
this.client,
this.path,
body,
this.headers,
params,
this.envelope,
(err, responseBody, headers, unpacked, statusCode) => {
resolve(this.handlePage(err, responseBody, headers, unpacked, statusCode));
}
);
});
const result = await Resource.put<T1>(this.client, this.path, body, this.headers, params, this.envelope, false);
return this.handlePage(result);
}

async patch<T1, T2>(params: Record<string, T2>, body: unknown): Promise<PaginatedResult<T1>> {
return new Promise((resolve) => {
Resource.patch(
this.client,
this.path,
body,
this.headers,
params,
this.envelope,
(err, responseBody, headers, unpacked, statusCode) => {
resolve(this.handlePage(err, responseBody, headers, unpacked, statusCode));
}
);
});
const result = await Resource.patch<T1>(this.client, this.path, body, this.headers, params, this.envelope, false);
return this.handlePage(result);
}

async handlePage<T>(
err: IPartialErrorInfo | null,
body: unknown,
headers: RequestCallbackHeaders | undefined,
unpacked: boolean | undefined,
statusCode: number | undefined
): Promise<PaginatedResult<T>> {
if (err && returnErrOnly(err, body, this.useHttpPaginatedResponse)) {
async handlePage<T>(result: ResourceResult<T>): Promise<PaginatedResult<T>> {
if (result.err && returnErrOnly(result.err, result.body, this.useHttpPaginatedResponse)) {
Logger.logAction(
Logger.LOG_ERROR,
'PaginatedResource.handlePage()',
'Unexpected error getting resource: err = ' + Utils.inspectError(err)
'Unexpected error getting resource: err = ' + Utils.inspectError(result.err)
);
throw err;
throw result.err;
}

let items, linkHeader, relParams;

try {
items = await this.bodyHandler(body, headers || {}, unpacked);
items = await this.bodyHandler(result.body, result.headers || {}, result.unpacked);
} catch (e) {
/* If we got an error, the failure to parse the body is almost certainly
* due to that, so throw that in preference over the parse error */
throw err || e;
throw result.err || e;
}

if (headers && (linkHeader = headers['Link'] || headers['link'])) {
if (result.headers && (linkHeader = result.headers['Link'] || result.headers['link'])) {
relParams = parseRelLinks(linkHeader);
}

if (this.useHttpPaginatedResponse) {
return new HttpPaginatedResponse(this, items, headers || {}, statusCode as number, relParams, err);
return new HttpPaginatedResponse(
this,
items,
result.headers || {},
result.statusCode as number,
relParams,
result.err
);
} else {
return new PaginatedResult(this, items, relParams);
}
Expand Down Expand Up @@ -220,18 +168,8 @@ export class PaginatedResult<T> {
* the rest of a multipage set of results can always be done with GET */
async get(params: any): Promise<PaginatedResult<T>> {
const res = this.resource;
return new Promise((resolve) => {
Resource.get(
res.client,
res.path,
res.headers,
params,
res.envelope,
function (err, body, headers, unpacked, statusCode) {
resolve(res.handlePage<T>(err, body, headers, unpacked, statusCode));
}
);
});
const result = await Resource.get<T>(res.client, res.path, res.headers, params, res.envelope, false);
return res.handlePage(result);
}
}

Expand Down
142 changes: 55 additions & 87 deletions src/common/lib/client/push.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,7 @@ class Admin {
if (client.options.pushFullWait) Utils.mixin(params, { fullWait: 'true' });

const requestBody = Utils.encodeBody(body, client._MsgPack, format);
return new Promise((resolve, reject) => {
Resource.post(client, '/push/publish', requestBody, headers, params, null, (err) =>
err ? reject(err) : resolve()
);
});
await Resource.post(client, '/push/publish', requestBody, headers, params, null, true);
}
}

Expand All @@ -67,27 +63,21 @@ class DeviceRegistrations {
if (client.options.pushFullWait) Utils.mixin(params, { fullWait: 'true' });

const requestBody = Utils.encodeBody(body, client._MsgPack, format);
return new Promise((resolve, reject) => {
Resource.put(
client,
'/push/deviceRegistrations/' + encodeURIComponent(device.id),
requestBody,
headers,
params,
null,
(err, body, headers, unpacked) => {
err
? reject(err)
: resolve(
DeviceDetails.fromResponseBody(
body as Record<string, unknown>,
client._MsgPack,
unpacked ? undefined : format
) as DeviceDetails
);
}
);
});
const response = await Resource.put(
client,
'/push/deviceRegistrations/' + encodeURIComponent(device.id),
requestBody,
headers,
params,
null,
true
);

return DeviceDetails.fromResponseBody(
response.body as Record<string, unknown>,
client._MsgPack,
response.unpacked ? undefined : format
) as DeviceDetails;
}

async get(deviceIdOrDetails: any): Promise<DeviceDetails> {
Expand All @@ -106,26 +96,20 @@ class DeviceRegistrations {

Utils.mixin(headers, client.options.headers);

return new Promise((resolve, reject) => {
Resource.get(
client,
'/push/deviceRegistrations/' + encodeURIComponent(deviceId),
headers,
{},
null,
function (err, body, headers, unpacked) {
err
? reject(err)
: resolve(
DeviceDetails.fromResponseBody(
body as Record<string, unknown>,
client._MsgPack,
unpacked ? undefined : format
) as DeviceDetails
);
}
);
});
const response = await Resource.get(
client,
'/push/deviceRegistrations/' + encodeURIComponent(deviceId),
headers,
{},
null,
true
);

return DeviceDetails.fromResponseBody(
response.body as Record<string, unknown>,
client._MsgPack,
response.unpacked ? undefined : format
) as DeviceDetails;
}

async list(params: any): Promise<PaginatedResult<unknown>> {
Expand Down Expand Up @@ -168,16 +152,14 @@ class DeviceRegistrations {

if (client.options.pushFullWait) Utils.mixin(params, { fullWait: 'true' });

return new Promise((resolve, reject) => {
Resource['delete'](
client,
'/push/deviceRegistrations/' + encodeURIComponent(deviceId),
headers,
params,
null,
(err) => (err ? reject(err) : resolve())
);
});
await Resource['delete'](
client,
'/push/deviceRegistrations/' + encodeURIComponent(deviceId),
headers,
params,
null,
true
);
}

async removeWhere(params: any): Promise<void> {
Expand All @@ -189,11 +171,7 @@ class DeviceRegistrations {

if (client.options.pushFullWait) Utils.mixin(params, { fullWait: 'true' });

return new Promise((resolve, reject) => {
Resource['delete'](client, '/push/deviceRegistrations', headers, params, null, (err) =>
err ? reject(err) : resolve()
);
});
await Resource['delete'](client, '/push/deviceRegistrations', headers, params, null, true);
}
}

Expand All @@ -216,27 +194,21 @@ class ChannelSubscriptions {
if (client.options.pushFullWait) Utils.mixin(params, { fullWait: 'true' });

const requestBody = Utils.encodeBody(body, client._MsgPack, format);
return new Promise((resolve, reject) => {
Resource.post(
client,
'/push/channelSubscriptions',
requestBody,
headers,
params,
null,
function (err, body, headers, unpacked) {
err
? reject(err)
: resolve(
PushChannelSubscription.fromResponseBody(
body as Record<string, any>,
client._MsgPack,
unpacked ? undefined : format
) as PushChannelSubscription
);
}
);
});
const response = await Resource.post(
client,
'/push/channelSubscriptions',
requestBody,
headers,
params,
null,
true
);

return PushChannelSubscription.fromResponseBody(
response.body as Record<string, any>,
client._MsgPack,
response.unpacked ? undefined : format
) as PushChannelSubscription;
}

async list(params: any): Promise<PaginatedResult<unknown>> {
Expand Down Expand Up @@ -269,11 +241,7 @@ class ChannelSubscriptions {

if (client.options.pushFullWait) Utils.mixin(params, { fullWait: 'true' });

return new Promise((resolve, reject) => {
Resource['delete'](client, '/push/channelSubscriptions', headers, params, null, (err) =>
err ? reject(err) : resolve()
);
});
await Resource['delete'](client, '/push/channelSubscriptions', headers, params, null, true);
}

/* ChannelSubscriptions have no unique id; removing one is equivalent to removeWhere by its properties */
Expand Down
Loading

0 comments on commit 033501d

Please sign in to comment.