Skip to content

Commit

Permalink
Update the api client to response the status code
Browse files Browse the repository at this point in the history
  • Loading branch information
nazarhussain committed Jan 16, 2023
1 parent e99f6ba commit 923137f
Show file tree
Hide file tree
Showing 36 changed files with 1,648 additions and 338 deletions.
18 changes: 15 additions & 3 deletions packages/api/src/beacon/client/beacon.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import {IChainForkConfig} from "@lodestar/config";
import {Api, ReqTypes, routesData, getReqSerializers, getReturnTypes} from "../routes/beacon/index.js";
import {IHttpClient, generateGenericJsonClient} from "../../utils/client/index.js";
import {IHttpClient, generateGenericJsonClient, ClientOptions} from "../../utils/client/index.js";
import {ReturnTypes} from "../../utils/types.js";
import {defaultClientOptions} from "./index.js";

/**
* REST HTTP client for beacon routes
*/
export function getClient(config: IChainForkConfig, httpClient: IHttpClient): Api {
export function getClient<ErrorAsResponse extends boolean = false>(
config: IChainForkConfig,
httpClient: IHttpClient,
options?: ClientOptions<ErrorAsResponse>
): Api<ErrorAsResponse> {
const reqSerializers = getReqSerializers(config);
const returnTypes = getReturnTypes();
// All routes return JSON, use a client auto-generator
return generateGenericJsonClient<Api, ReqTypes>(routesData, reqSerializers, returnTypes, httpClient);
return generateGenericJsonClient<Api<ErrorAsResponse>, ReqTypes, ErrorAsResponse>(
routesData,
reqSerializers,
returnTypes as ReturnTypes<Api<ErrorAsResponse>>,
httpClient,
options ?? (defaultClientOptions as ClientOptions<ErrorAsResponse>)
);
}
20 changes: 16 additions & 4 deletions packages/api/src/beacon/client/config.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import {IChainForkConfig} from "@lodestar/config";
import {Api, ReqTypes, routesData, getReqSerializers, getReturnTypes} from "../routes/config.js";
import {IHttpClient, generateGenericJsonClient} from "../../utils/client/index.js";
import {ClientOptions, generateGenericJsonClient, IHttpClient} from "../../utils/client/index.js";
import {ReturnTypes} from "../../utils/types.js";
import {Api, getReqSerializers, getReturnTypes, ReqTypes, routesData} from "../routes/config.js";
import {defaultClientOptions} from "./index.js";

/**
* REST HTTP client for config routes
*/
export function getClient(config: IChainForkConfig, httpClient: IHttpClient): Api {
export function getClient<ErrorAsResponse extends boolean = false>(
config: IChainForkConfig,
httpClient: IHttpClient,
options?: ClientOptions<ErrorAsResponse>
): Api<ErrorAsResponse> {
const reqSerializers = getReqSerializers();
const returnTypes = getReturnTypes();
// All routes return JSON, use a client auto-generator
return generateGenericJsonClient<Api, ReqTypes>(routesData, reqSerializers, returnTypes, httpClient);
return generateGenericJsonClient<Api<ErrorAsResponse>, ReqTypes, ErrorAsResponse>(
routesData,
reqSerializers,
returnTypes as ReturnTypes<Api<ErrorAsResponse>>,
httpClient,
options ?? (defaultClientOptions as ClientOptions<ErrorAsResponse>)
);
}
54 changes: 41 additions & 13 deletions packages/api/src/beacon/client/debug.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,77 @@
import {IChainForkConfig} from "@lodestar/config";
import {Api, ReqTypes, routesData, getReqSerializers, getReturnTypes, StateFormat} from "../routes/debug.js";
import {IHttpClient, getFetchOptsSerializers, generateGenericJsonClient} from "../../utils/client/index.js";
import {
ClientOptions,
generateGenericJsonClient,
getFetchOptsSerializers,
IHttpClient,
} from "../../utils/client/index.js";
import {ReturnTypes} from "../../utils/types.js";
import {StateId} from "../routes/beacon/state.js";
import {Api, getReqSerializers, getReturnTypes, ReqTypes, routesData, StateFormat} from "../routes/debug.js";
import {defaultClientOptions} from "./index.js";

// As Jul 2022, it takes up to 3 mins to download states so make this 5 mins for reservation
const GET_STATE_TIMEOUT_MS = 5 * 60 * 1000;

/**
* REST HTTP client for debug routes
*/
export function getClient(_config: IChainForkConfig, httpClient: IHttpClient): Api {
export function getClient<ErrorAsResponse extends boolean = false>(
_config: IChainForkConfig,
httpClient: IHttpClient,
options?: ClientOptions<ErrorAsResponse>
): Api<ErrorAsResponse> {
const reqSerializers = getReqSerializers();
const returnTypes = getReturnTypes();
// Some routes return JSON, use a client auto-generator
const client = generateGenericJsonClient<Api, ReqTypes>(routesData, reqSerializers, returnTypes, httpClient);
const client = generateGenericJsonClient<Api<ErrorAsResponse>, ReqTypes, ErrorAsResponse>(
routesData,
reqSerializers,
returnTypes as ReturnTypes<Api<ErrorAsResponse>>,
httpClient,
options ?? (defaultClientOptions as ClientOptions<ErrorAsResponse>)
);
// For `getState()` generate request serializer
const fetchOptsSerializers = getFetchOptsSerializers<Api, ReqTypes>(routesData, reqSerializers);

return {
...client,

// TODO: Debug the type issue
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
async getState(stateId: string, format?: StateFormat) {
if (format === "ssz") {
const buffer = await httpClient.arrayBuffer({
const res = await httpClient.arrayBuffer({
...fetchOptsSerializers.getState(stateId, format),
timeoutMs: GET_STATE_TIMEOUT_MS,
});
// Casting to any otherwise Typescript doesn't like the multi-type return
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-explicit-any
return new Uint8Array(buffer) as any;
} else {
return client.getState(stateId, format);
return {
ok: true,
res: {data: new Uint8Array(res.body)},
status: 200,
};
}
return client.getState(stateId, format);
},
async getStateV2(stateId: string, format?: StateFormat) {

// TODO: Debug the type issue
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
async getStateV2(stateId: StateId, format?: StateFormat) {
if (format === "ssz") {
const buffer = await httpClient.arrayBuffer({
const res = await httpClient.arrayBuffer({
...fetchOptsSerializers.getStateV2(stateId, format),
timeoutMs: GET_STATE_TIMEOUT_MS,
});
// Casting to any otherwise Typescript doesn't like the multi-type return
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-explicit-any
return new Uint8Array(buffer) as any;
} else {
return client.getStateV2(stateId, format);
return {ok: true, res: {data: new Uint8Array(res.body)}, status: res.status};
}

return client.getStateV2(stateId, format);
},
};
}
3 changes: 3 additions & 0 deletions packages/api/src/beacon/client/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {IChainForkConfig} from "@lodestar/config";
import {Api, BeaconEvent, routesData, getEventSerdes} from "../routes/events.js";
import {stringifyQuery} from "../../utils/client/format.js";
import {getEventSource} from "../../utils/client/eventSource.js";
import {HttpStatusCode} from "../../utils/client/httpStatusCode.js";

/**
* REST HTTP client for events routes
Expand Down Expand Up @@ -50,6 +51,8 @@ export function getClient(_config: IChainForkConfig, baseUrl: string): Api {
} finally {
eventSource.close();
}

return {ok: true, res: undefined, status: HttpStatusCode.OK};
},
};
}
Expand Down
34 changes: 24 additions & 10 deletions packages/api/src/beacon/client/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import {IChainForkConfig} from "@lodestar/config";
import {Api} from "../routes/index.js";
import {IHttpClient, HttpClient, HttpClientOptions, HttpClientModules} from "../../utils/client/index.js";
import {
IHttpClient,
HttpClient,
HttpClientOptions,
HttpClientModules,
ClientOptions,
} from "../../utils/client/index.js";

import * as beacon from "./beacon.js";
import * as configApi from "./config.js";
Expand All @@ -17,22 +23,30 @@ type ClientModules = HttpClientModules & {
httpClient?: IHttpClient;
};

export const defaultClientOptions: ClientOptions<false> = {
errorAsResponse: false,
};

/**
* REST HTTP client for all routes
*/
export function getClient(opts: HttpClientOptions, modules: ClientModules): Api {
export function getClient<ErrorAsResponse extends boolean = false>(
opts: HttpClientOptions,
modules: ClientModules,
options?: ClientOptions<ErrorAsResponse>
): Api<ErrorAsResponse> {
const {config} = modules;
const httpClient = modules.httpClient ?? new HttpClient(opts, modules);

return {
beacon: beacon.getClient(config, httpClient),
config: configApi.getClient(config, httpClient),
debug: debug.getClient(config, httpClient),
beacon: beacon.getClient<ErrorAsResponse>(config, httpClient, options),
config: configApi.getClient<ErrorAsResponse>(config, httpClient, options),
debug: debug.getClient<ErrorAsResponse>(config, httpClient, options),
events: events.getClient(config, httpClient.baseUrl),
lightclient: lightclient.getClient(config, httpClient),
lodestar: lodestar.getClient(config, httpClient),
node: node.getClient(config, httpClient),
proof: proof.getClient(config, httpClient),
validator: validator.getClient(config, httpClient),
lightclient: lightclient.getClient<ErrorAsResponse>(config, httpClient, options),
lodestar: lodestar.getClient<ErrorAsResponse>(config, httpClient, options),
node: node.getClient<ErrorAsResponse>(config, httpClient, options),
proof: proof.getClient<ErrorAsResponse>(config, httpClient, options),
validator: validator.getClient<ErrorAsResponse>(config, httpClient, options),
};
}
18 changes: 15 additions & 3 deletions packages/api/src/beacon/client/lightclient.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import {IChainForkConfig} from "@lodestar/config";
import {Api, ReqTypes, routesData, getReqSerializers, getReturnTypes} from "../routes/lightclient.js";
import {IHttpClient, generateGenericJsonClient} from "../../utils/client/index.js";
import {IHttpClient, generateGenericJsonClient, ClientOptions} from "../../utils/client/index.js";
import {ReturnTypes} from "../../utils/types.js";
import {defaultClientOptions} from "./index.js";

/**
* REST HTTP client for lightclient routes
*/
export function getClient(_config: IChainForkConfig, httpClient: IHttpClient): Api {
export function getClient<ErrorAsResponse extends boolean = false>(
_config: IChainForkConfig,
httpClient: IHttpClient,
options?: ClientOptions<ErrorAsResponse>
): Api<ErrorAsResponse> {
const reqSerializers = getReqSerializers();
const returnTypes = getReturnTypes();
// All routes return JSON, use a client auto-generator
return generateGenericJsonClient<Api, ReqTypes>(routesData, reqSerializers, returnTypes, httpClient);
return generateGenericJsonClient<Api<ErrorAsResponse>, ReqTypes, ErrorAsResponse>(
routesData,
reqSerializers,
returnTypes as ReturnTypes<Api<ErrorAsResponse>>,
httpClient,
options ?? (defaultClientOptions as ClientOptions<ErrorAsResponse>)
);
}
18 changes: 15 additions & 3 deletions packages/api/src/beacon/client/lodestar.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import {IChainForkConfig} from "@lodestar/config";
import {Api, ReqTypes, routesData, getReqSerializers, getReturnTypes} from "../routes/lodestar.js";
import {IHttpClient, generateGenericJsonClient} from "../../utils/client/index.js";
import {IHttpClient, generateGenericJsonClient, ClientOptions} from "../../utils/client/index.js";
import {ReturnTypes} from "../../utils/types.js";
import {defaultClientOptions} from "./index.js";

/**
* REST HTTP client for lodestar routes
*/
export function getClient(_config: IChainForkConfig, httpClient: IHttpClient): Api {
export function getClient<ErrorAsResponse extends boolean = false>(
_config: IChainForkConfig,
httpClient: IHttpClient,
options?: ClientOptions<ErrorAsResponse>
): Api<ErrorAsResponse> {
const reqSerializers = getReqSerializers();
const returnTypes = getReturnTypes();
// All routes return JSON, use a client auto-generator
return generateGenericJsonClient<Api, ReqTypes>(routesData, reqSerializers, returnTypes, httpClient);
return generateGenericJsonClient<Api<ErrorAsResponse>, ReqTypes, ErrorAsResponse>(
routesData,
reqSerializers,
returnTypes as ReturnTypes<Api<ErrorAsResponse>>,
httpClient,
options ?? (defaultClientOptions as ClientOptions<ErrorAsResponse>)
);
}
28 changes: 16 additions & 12 deletions packages/api/src/beacon/client/node.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
import {IChainForkConfig} from "@lodestar/config";
import {generateGenericJsonClient, getFetchOptsSerializers, IHttpClient} from "../../utils/client/index.js";
import {Api, getReqSerializers, getReturnTypes, NodeHealth, ReqTypes, routesData} from "../routes/node.js";
import {ClientOptions, generateGenericJsonClient, IHttpClient} from "../../utils/client/index.js";
import {APIServerHandlers} from "../../utils/types.js";
import {Api, getReqSerializers, getReturnTypes, ReqTypes, routesData} from "../routes/node.js";
import {defaultClientOptions} from "./index.js";

/**
* REST HTTP client for beacon routes
*/
export function getClient(_config: IChainForkConfig, httpClient: IHttpClient): Api {
export function getClient<ErrorAsResponse extends boolean = false>(
_config: IChainForkConfig,
httpClient: IHttpClient,
options?: ClientOptions<ErrorAsResponse>
): Api<ErrorAsResponse> {
const reqSerializers = getReqSerializers();
const returnTypes = getReturnTypes();
// All routes return JSON, use a client auto-generator
const client = generateGenericJsonClient<Api, ReqTypes>(routesData, reqSerializers, returnTypes, httpClient);
const fetchOptsSerializers = getFetchOptsSerializers<Api, ReqTypes>(routesData, reqSerializers);

return {
...client,
async getHealth(): Promise<NodeHealth> {
return httpClient.request({...fetchOptsSerializers.getHealth()});
},
};
return generateGenericJsonClient<Api<ErrorAsResponse>, ReqTypes, ErrorAsResponse>(
routesData,
reqSerializers,
returnTypes,
httpClient,
options ?? (defaultClientOptions as ClientOptions<ErrorAsResponse>)
);
}
38 changes: 32 additions & 6 deletions packages/api/src/beacon/client/proof.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,48 @@
import {IChainForkConfig} from "@lodestar/config";
import {deserializeProof} from "@chainsafe/persistent-merkle-tree";
import {deserializeProof, Proof} from "@chainsafe/persistent-merkle-tree";
import {Api, ReqTypes, routesData, getReqSerializers} from "../routes/proof.js";
import {IHttpClient, getFetchOptsSerializers} from "../../utils/client/index.js";
import {IHttpClient, getFetchOptsSerializers, ClientOptions, HttpError} from "../../utils/client/index.js";
import {HttpStatusCode} from "../../utils/client/httpStatusCode.js";
import {APIClientResponse} from "../../utils/types.js";

/**
* REST HTTP client for lightclient routes
*/
export function getClient(_config: IChainForkConfig, httpClient: IHttpClient): Api {
export function getClient<ErrorAsResponse extends boolean = false>(
_config: IChainForkConfig,
httpClient: IHttpClient,
options?: ClientOptions<ErrorAsResponse>
): Api<ErrorAsResponse> {
const reqSerializers = getReqSerializers();

// For `getStateProof()` generate request serializer
const fetchOptsSerializers = getFetchOptsSerializers<Api, ReqTypes>(routesData, reqSerializers);

return {
async getStateProof(stateId, paths) {
const buffer = await httpClient.arrayBuffer(fetchOptsSerializers.getStateProof(stateId, paths));
const proof = deserializeProof(new Uint8Array(buffer));
return {data: proof};
try {
const res = await httpClient.arrayBuffer(fetchOptsSerializers.getStateProof(stateId, paths));
const proof = deserializeProof(new Uint8Array(res.body));

return {ok: true, res: {data: proof}, status: HttpStatusCode.OK} as APIClientResponse<
{[HttpStatusCode.OK]: {data: Proof}},
HttpStatusCode.INTERNAL_SERVER_ERROR,
ErrorAsResponse
>;
} catch (err) {
if (err instanceof HttpError && options?.errorAsResponse) {
return {
ok: false,
res: {code: err.status, message: err.message},
status: err.status,
} as APIClientResponse<
{[HttpStatusCode.OK]: {data: Proof}},
HttpStatusCode.INTERNAL_SERVER_ERROR,
ErrorAsResponse
>;
}
throw err;
}
},
};
}
Loading

0 comments on commit 923137f

Please sign in to comment.