Skip to content

Commit

Permalink
3.0.0: Fix remaining REST untyped responses (#882)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonpaulos authored Aug 15, 2024
1 parent c3a56c3 commit ceccfe4
Show file tree
Hide file tree
Showing 75 changed files with 3,042 additions and 626 deletions.
111 changes: 63 additions & 48 deletions src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,60 @@ interface ErrorWithAdditionalInfo extends Error {
statusCode: number;
}

export interface HTTPClientResponse {
body: Uint8Array | any; // when content-type=JSON, body is a JSON object, otherwise it's a Uint8Array
export class HTTPClientResponse {
/**
* The raw response bytes
*/
body: Uint8Array;
/**
* If the expected response type is JSON, this is the response bytes converted to a string.
*/
text?: string;
format: 'application/msgpack' | 'application/json';
headers: Record<string, string>;
status: number;
ok: boolean;

constructor(options: {
body: Uint8Array;
text?: string;
format: 'application/msgpack' | 'application/json';
headers: Record<string, string>;
status: number;
ok: boolean;
}) {
this.body = options.body;
this.text = options.text;
this.format = options.format;
this.headers = options.headers;
this.status = options.status;
this.ok = options.ok;
}

/**
* Returns the response body as a string, ready to be parsed as JSON.
*/
getJSONText(): string {
if (this.text === undefined) {
throw new Error(
`Response body does not contain JSON data. Format is ${this.format}`
);
}
return this.text;
}

/**
* Parses the response body as JSON with the given options.
*/
parseBodyAsJSON(jsonOptions: utils.ParseJSONOptions) {
if (this.text === undefined) {
throw new Error(
`Response body does not contain JSON data. Format is ${this.format}`
);
}
// eslint-disable-next-line no-use-before-define
return HTTPClient.parseJSON(this.text, this.status, jsonOptions);
}
}

/**
Expand Down Expand Up @@ -175,27 +223,21 @@ export class HTTPClient {
*/
private static prepareResponse(
res: BaseHTTPClientResponse,
format: 'application/msgpack' | 'application/json',
parseBody: boolean,
jsonOptions: utils.ParseJSONOptions
format: 'application/msgpack' | 'application/json'
): HTTPClientResponse {
let { body } = res;
const { body } = res;
let text: string | undefined;

if (format !== 'application/msgpack') {
text = (body && new TextDecoder().decode(body)) || '';
}

if (parseBody && format === 'application/json') {
body = HTTPClient.parseJSON(text!, res.status, jsonOptions);
}

return {
return new HTTPClientResponse({
...res,
body,
format,
text,
ok: Math.trunc(res.status / 100) === 2,
};
});
}

/**
Expand All @@ -204,17 +246,12 @@ export class HTTPClient {
* by adding the status and preparing the internal response
* @private
*/
private static prepareResponseError(
err: any,
jsonOptions: utils.ParseJSONOptions
) {
private static prepareResponseError(err: any) {
if (err.response) {
// eslint-disable-next-line no-param-reassign
err.response = HTTPClient.prepareResponse(
err.response,
'application/json',
true,
jsonOptions
'application/json'
);
// eslint-disable-next-line no-param-reassign
err.status = err.response.status;
Expand All @@ -237,16 +274,12 @@ export class HTTPClient {
*/
async get({
relativePath,
jsonOptions,
query,
requestHeaders,
parseBody,
}: {
relativePath: string;
jsonOptions: utils.ParseJSONOptions;
query?: Query<any>;
requestHeaders?: Record<string, string>;
parseBody: boolean;
}): Promise<HTTPClientResponse> {
const format = getAcceptFormat(query);
const fullHeaders = { ...(requestHeaders ?? {}), accept: format };
Expand All @@ -258,9 +291,9 @@ export class HTTPClient {
fullHeaders
);

return HTTPClient.prepareResponse(res, format, parseBody, jsonOptions);
return HTTPClient.prepareResponse(res, format);
} catch (err) {
throw HTTPClient.prepareResponseError(err, jsonOptions);
throw HTTPClient.prepareResponseError(err);
}
}

Expand All @@ -273,17 +306,13 @@ export class HTTPClient {
async post({
relativePath,
data,
jsonOptions,
query,
requestHeaders,
parseBody,
}: {
relativePath: string;
data: any;
jsonOptions: utils.ParseJSONOptions;
query?: Query<any>;
requestHeaders?: Record<string, string>;
parseBody: boolean;
}): Promise<HTTPClientResponse> {
const fullHeaders = {
'content-type': 'application/json',
Expand All @@ -298,14 +327,9 @@ export class HTTPClient {
fullHeaders
);

return HTTPClient.prepareResponse(
res,
'application/json',
parseBody,
jsonOptions
);
return HTTPClient.prepareResponse(res, 'application/json');
} catch (err) {
throw HTTPClient.prepareResponseError(err, jsonOptions);
throw HTTPClient.prepareResponseError(err);
}
}

Expand All @@ -318,15 +342,11 @@ export class HTTPClient {
async delete({
relativePath,
data,
jsonOptions,
requestHeaders,
parseBody,
}: {
relativePath: string;
data: any;
jsonOptions: utils.ParseJSONOptions;
requestHeaders?: Record<string, string>;
parseBody: boolean;
}) {
const fullHeaders = {
'content-type': 'application/json',
Expand All @@ -343,14 +363,9 @@ export class HTTPClient {
fullHeaders
);

return HTTPClient.prepareResponse(
res,
'application/json',
parseBody,
jsonOptions
);
return HTTPClient.prepareResponse(res, 'application/json');
} catch (err) {
throw HTTPClient.prepareResponseError(err, jsonOptions);
throw HTTPClient.prepareResponseError(err);
}
}
}
30 changes: 12 additions & 18 deletions src/client/kmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,39 +21,33 @@ export class KmdClient extends ServiceClient {
private async get(relativePath: string): Promise<any> {
const res = await this.c.get({
relativePath,
jsonOptions: {
// Using SAFE for all KMD endpoints because no integers in responses should ever be too big
intDecoding: IntDecoding.SAFE,
},
parseBody: true,
});
return res.body;
return res.parseBodyAsJSON({
// Using SAFE for all KMD endpoints because no integers in responses should ever be too big
intDecoding: IntDecoding.SAFE,
});
}

private async delete(relativePath: string, data: any): Promise<any> {
const res = await this.c.delete({
relativePath,
data,
jsonOptions: {
// Using SAFE for all KMD endpoints because no integers in responses should ever be too big
intDecoding: IntDecoding.SAFE,
},
parseBody: true,
});
return res.body;
return res.parseBodyAsJSON({
// Using SAFE for all KMD endpoints because no integers in responses should ever be too big
intDecoding: IntDecoding.SAFE,
});
}

private async post(relativePath: string, data: any): Promise<any> {
const res = await this.c.post({
relativePath,
data,
parseBody: true,
jsonOptions: {
// Using SAFE for all KMD endpoints because no integers in responses should ever be too big
intDecoding: IntDecoding.SAFE,
},
});
return res.body;
return res.parseBodyAsJSON({
// Using SAFE for all KMD endpoints because no integers in responses should ever be too big
intDecoding: IntDecoding.SAFE,
});
}

/**
Expand Down
14 changes: 5 additions & 9 deletions src/client/v2/algod/accountApplicationInformation.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import JSONRequest from '../jsonrequest.js';
import { HTTPClient } from '../../client.js';
import { HTTPClient, HTTPClientResponse } from '../../client.js';
import { decodeJSON } from '../../../encoding/encoding.js';
import { AccountApplicationResponse } from './models/types.js';
import { Address } from '../../../encoding/address.js';

export default class AccountApplicationInformation extends JSONRequest<
AccountApplicationResponse,
Record<string, any>
> {
export default class AccountApplicationInformation extends JSONRequest<AccountApplicationResponse> {
private account: string;

constructor(
Expand All @@ -23,9 +21,7 @@ export default class AccountApplicationInformation extends JSONRequest<
}

// eslint-disable-next-line class-methods-use-this
prepare(body: Record<string, any>): AccountApplicationResponse {
return AccountApplicationResponse.fromEncodingData(
AccountApplicationResponse.encodingSchema.fromPreparedJSON(body)
);
prepare(response: HTTPClientResponse): AccountApplicationResponse {
return decodeJSON(response.getJSONText(), AccountApplicationResponse);
}
}
14 changes: 5 additions & 9 deletions src/client/v2/algod/accountAssetInformation.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import JSONRequest from '../jsonrequest.js';
import { HTTPClient } from '../../client.js';
import { HTTPClient, HTTPClientResponse } from '../../client.js';
import { decodeJSON } from '../../../encoding/encoding.js';
import { AccountAssetResponse } from './models/types.js';
import { Address } from '../../../encoding/address.js';

export default class AccountAssetInformation extends JSONRequest<
AccountAssetResponse,
Record<string, any>
> {
export default class AccountAssetInformation extends JSONRequest<AccountAssetResponse> {
private account: string;

constructor(
Expand All @@ -23,9 +21,7 @@ export default class AccountAssetInformation extends JSONRequest<
}

// eslint-disable-next-line class-methods-use-this
prepare(body: Record<string, any>): AccountAssetResponse {
return AccountAssetResponse.fromEncodingData(
AccountAssetResponse.encodingSchema.fromPreparedJSON(body)
);
prepare(response: HTTPClientResponse): AccountAssetResponse {
return decodeJSON(response.getJSONText(), AccountAssetResponse);
}
}
14 changes: 5 additions & 9 deletions src/client/v2/algod/accountInformation.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import JSONRequest from '../jsonrequest.js';
import { HTTPClient } from '../../client.js';
import { HTTPClient, HTTPClientResponse } from '../../client.js';
import { decodeJSON } from '../../../encoding/encoding.js';
import { Account } from './models/types.js';
import { Address } from '../../../encoding/address.js';

export default class AccountInformation extends JSONRequest<
Account,
Record<string, any>
> {
export default class AccountInformation extends JSONRequest<Account> {
private account: string;

constructor(c: HTTPClient, account: string | Address) {
Expand Down Expand Up @@ -38,9 +36,7 @@ export default class AccountInformation extends JSONRequest<
}

// eslint-disable-next-line class-methods-use-this
prepare(body: Record<string, any>): Account {
return Account.fromEncodingData(
Account.encodingSchema.fromPreparedJSON(body)
);
prepare(response: HTTPClientResponse): Account {
return decodeJSON(response.getJSONText(), Account);
}
}
10 changes: 5 additions & 5 deletions src/client/v2/algod/block.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import * as encoding from '../../../encoding/encoding.js';
import JSONRequest from '../jsonrequest.js';
import { HTTPClient } from '../../client.js';
import { HTTPClient, HTTPClientResponse } from '../../client.js';
import { decodeMsgpack } from '../../../encoding/encoding.js';
import { BlockResponse } from './models/types.js';

/**
* block gets the block info for the given round. this call may block
*/
export default class Block extends JSONRequest<BlockResponse, Uint8Array> {
export default class Block extends JSONRequest<BlockResponse> {
private round: number;

constructor(c: HTTPClient, roundNumber: number) {
Expand All @@ -20,7 +20,7 @@ export default class Block extends JSONRequest<BlockResponse, Uint8Array> {
}

// eslint-disable-next-line class-methods-use-this
prepare(body: Uint8Array): BlockResponse {
return encoding.decodeMsgpack(body, BlockResponse);
prepare(response: HTTPClientResponse): BlockResponse {
return decodeMsgpack(response.body, BlockResponse);
}
}
Loading

0 comments on commit ceccfe4

Please sign in to comment.