Skip to content

Commit

Permalink
Update API response object (#4994)
Browse files Browse the repository at this point in the history
* Use http status for node health

* Write only the header for the node health

* Update the comment

* Remove unncessary await

* Remove unncessary await

* Update api test data

* Fix lint error

* Update the api client to response the status code

* Rename res prop to response

* Fix unit tests

* Export common types

* Fix validator package

* Fix all packages

* Fix some code break in merge conflicts

* Fix type erorrs for all packages

* Update the readme for the api package

* Fix lint errors

* Fix endpoint sim test

* Fix e2e tests

* Update api package to remove optional error response

* Update the api error response and assertion

* Fix few breaking tests

* Fix failing tests

* Fix failing e2e test
  • Loading branch information
nazarhussain authored Jan 20, 2023
1 parent 8aea8ca commit 460ba59
Show file tree
Hide file tree
Showing 131 changed files with 1,952 additions and 699 deletions.
12 changes: 10 additions & 2 deletions packages/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ Typescript REST client for the [Ethereum Consensus API spec](https://github.com/

## Usage

We use more typesafe approach for the API client, where all the errors are returned not thrown. This approach is more easy to document and better to handle all possible error cases.

```typescript
import {getClient} from "@lodestar/api";
import {getClient, HttpError} from "@lodestar/api";
import {config} from "@lodestar/config/default";

const api = getClient({baseUrl: "http://localhost:9596"}, {config});
Expand All @@ -22,7 +24,13 @@ api.beacon
"head",
"0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95"
)
.then((res) => console.log("Your balance is:", res.data.balance));
.then((res) => {
if(res.ok) {
console.log("Your balance is:", res.response.data.balance, res.ok, res.status);
} else {
console.error(res.status, res.error.code, res.error.message);
}
});
```

## Prerequisites
Expand Down
8 changes: 7 additions & 1 deletion packages/api/src/beacon/client/beacon.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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 {ReturnTypes} from "../../utils/types.js";

/**
* REST HTTP client for beacon routes
Expand All @@ -9,5 +10,10 @@ export function getClient(config: IChainForkConfig, httpClient: IHttpClient): Ap
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, ReqTypes>(
routesData,
reqSerializers,
returnTypes as ReturnTypes<Api>,
httpClient
);
}
12 changes: 9 additions & 3 deletions packages/api/src/beacon/client/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {IChainForkConfig} from "@lodestar/config";
import {Api, ReqTypes, routesData, getReqSerializers, getReturnTypes} from "../routes/config.js";
import {IHttpClient, generateGenericJsonClient} from "../../utils/client/index.js";
import {generateGenericJsonClient, IHttpClient} from "../../utils/client/index.js";
import {ReturnTypes} from "../../utils/types.js";
import {Api, getReqSerializers, getReturnTypes, ReqTypes, routesData} from "../routes/config.js";

/**
* REST HTTP client for config routes
Expand All @@ -9,5 +10,10 @@ export function getClient(config: IChainForkConfig, httpClient: IHttpClient): Ap
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, ReqTypes>(
routesData,
reqSerializers,
returnTypes as ReturnTypes<Api>,
httpClient
);
}
45 changes: 33 additions & 12 deletions packages/api/src/beacon/client/debug.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
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 {ApiClientResponse} from "../../interfaces.js";
import {HttpStatusCode} from "../../utils/client/httpStatusCode.js";
import {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";

// 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;
Expand All @@ -12,38 +16,55 @@ export function getClient(_config: IChainForkConfig, httpClient: IHttpClient): A
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, ReqTypes>(
routesData,
reqSerializers,
returnTypes as ReturnTypes<Api>,
httpClient
);
// 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,
response: new Uint8Array(res.body),
status: res.status,
} as ApiClientResponse<{[HttpStatusCode.OK]: Uint8Array}>;
}
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, response: new Uint8Array(res.body), status: res.status} as ApiClientResponse<{
[HttpStatusCode.OK]: Uint8Array;
}>;
}

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, response: undefined, status: HttpStatusCode.OK};
},
};
}
Expand Down
8 changes: 7 additions & 1 deletion packages/api/src/beacon/client/lightclient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {IChainForkConfig} from "@lodestar/config";
import {Api, ReqTypes, routesData, getReqSerializers, getReturnTypes} from "../routes/lightclient.js";
import {IHttpClient, generateGenericJsonClient} from "../../utils/client/index.js";
import {ReturnTypes} from "../../utils/types.js";

/**
* REST HTTP client for lightclient routes
Expand All @@ -9,5 +10,10 @@ export function getClient(_config: IChainForkConfig, httpClient: IHttpClient): A
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, ReqTypes>(
routesData,
reqSerializers,
returnTypes as ReturnTypes<Api>,
httpClient
);
}
8 changes: 7 additions & 1 deletion packages/api/src/beacon/client/lodestar.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {IChainForkConfig} from "@lodestar/config";
import {Api, ReqTypes, routesData, getReqSerializers, getReturnTypes} from "../routes/lodestar.js";
import {IHttpClient, generateGenericJsonClient} from "../../utils/client/index.js";
import {ReturnTypes} from "../../utils/types.js";

/**
* REST HTTP client for lodestar routes
Expand All @@ -9,5 +10,10 @@ export function getClient(_config: IChainForkConfig, httpClient: IHttpClient): A
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, ReqTypes>(
routesData,
reqSerializers,
returnTypes as ReturnTypes<Api>,
httpClient
);
}
4 changes: 2 additions & 2 deletions packages/api/src/beacon/client/node.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {IChainForkConfig} from "@lodestar/config";
import {Api, ReqTypes, routesData, getReqSerializers, getReturnTypes} from "../routes/node.js";
import {IHttpClient, generateGenericJsonClient} from "../../utils/client/index.js";
import {generateGenericJsonClient, IHttpClient} from "../../utils/client/index.js";
import {Api, getReqSerializers, getReturnTypes, ReqTypes, routesData} from "../routes/node.js";

/**
* REST HTTP client for beacon routes
Expand Down
21 changes: 17 additions & 4 deletions packages/api/src/beacon/client/proof.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {IChainForkConfig} from "@lodestar/config";
import {deserializeProof} 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, HttpError} from "../../utils/client/index.js";
import {HttpStatusCode} from "../../utils/client/httpStatusCode.js";

/**
* REST HTTP client for lightclient routes
Expand All @@ -14,9 +15,21 @@ export function getClient(_config: IChainForkConfig, httpClient: IHttpClient): A

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, response: {data: proof}, status: HttpStatusCode.OK};
} catch (err) {
if (err instanceof HttpError) {
return {
ok: false,
error: {code: err.status, message: err.message, operationId: "proof.getStateProof"},
status: err.status,
};
}
throw err;
}
},
};
}
8 changes: 7 additions & 1 deletion packages/api/src/beacon/client/validator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {IChainForkConfig} from "@lodestar/config";
import {Api, ReqTypes, routesData, getReqSerializers, getReturnTypes} from "../routes/validator.js";
import {IHttpClient, generateGenericJsonClient} from "../../utils/client/index.js";
import {ReturnTypes} from "../../utils/types.js";

/**
* REST HTTP client for validator routes
Expand All @@ -9,5 +10,10 @@ export function getClient(_config: IChainForkConfig, httpClient: IHttpClient): A
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, ReqTypes>(
routesData,
reqSerializers,
returnTypes as ReturnTypes<Api>,
httpClient
);
}
Loading

0 comments on commit 460ba59

Please sign in to comment.