-
-
Notifications
You must be signed in to change notification settings - Fork 325
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update API response object #4994
Changes from 8 commits
04a7227
e73d173
9f4137d
a3865f4
9a7e52b
5388ca9
e99f6ba
923137f
cf88c52
1d44e81
1862dfa
b6bbc76
ebdb14c
74d6f5c
13be9fa
8bb4942
c206b38
ad0cd24
edbfaa4
b37b071
8309bc6
443cdde
1f2054b
dee59bb
916dba6
8559b71
f1c419b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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>) | ||
); | ||
} |
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>) | ||
); | ||
} |
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); | ||
}, | ||
}; | ||
} |
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>) | ||
); | ||
} |
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>) | ||
); | ||
} |
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/node.js"; | ||
import {IHttpClient, generateGenericJsonClient} from "../../utils/client/index.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 | ||
return generateGenericJsonClient<Api, ReqTypes>(routesData, reqSerializers, returnTypes, httpClient); | ||
return generateGenericJsonClient<Api<ErrorAsResponse>, ReqTypes, ErrorAsResponse>( | ||
routesData, | ||
reqSerializers, | ||
returnTypes, | ||
httpClient, | ||
options ?? (defaultClientOptions as ClientOptions<ErrorAsResponse>) | ||
); | ||
} |
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>( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you document the behavior of ErrorAsResponse somewhere? Seems that depending on the option passed, you can make errors either throw or return. Do we need both behaviors? Might be simpler to pick a convention (ie always return) and stick with it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @wemeetagain My preference is to use |
||
_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; | ||
} | ||
}, | ||
}; | ||
} |
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/validator.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 validator 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>) | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you also think about how we would be able to incorporate this? ethereum/beacon-APIs#250
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already have support for SZZ encoding for few endpoints, similarly we can support for others when required.
https://github.com/ethereum/beacon-APIs/blob/6669d981486b7034fc9911fdf7be157343b6ea5e/apis/debug/state.v2.yaml#L40-L42
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This beacon-apis PR is about systematically supporting SSZ for all endpoints, not just supporting one-by-one.
Edit: I'm not suggesting to tackle this in this PR, just more an FYI of possible improvement that will be desired.