rosetta-sdk-typescript
Version:
Typescript SDK to create and interact with Rosetta API implementations.
136 lines (124 loc) • 4.07 kB
text/typescript
import fetch from 'node-fetch';
import {
AccountApi,
AccountApiInterface,
BlockApi,
BlockApiInterface,
CallApi,
CallApiInterface,
Configuration,
ConstructionApi,
ConstructionApiInterface,
EventsApi,
EventsApiInterface,
MempoolApi,
MempoolApiInterface,
Middleware,
ModelErrorFromJSON,
NetworkApi,
NetworkApiInterface,
ResponseContext,
SearchApi,
SearchApiInterface,
} from 'rosetta-sdk-typescript';
/**
* Params used to create a client factory.
*/
interface RestClientFactoryParams {
/**
* The rest url of the Rosetta service. E.g: http://localhost:8080/
*/
url: string;
/**
* Optional fetch api.
*/
fetchApi?: unknown;
/**
* Middleware for pre/post request customizations.
*/
middleware?: Middleware[];
}
/**
* When the rest client raises an error, the error will be wrapped in this exception.
*/
export class RestClientCallError extends Error {
/**
*
* @param message - the message resolved from the error response
* @param statusCode - the response status code
* @param statusMessage - the response status message
* @param body - the body as string
*/
constructor(message: string, public readonly statusCode: number, public readonly statusMessage: string, public readonly body: string) {
super(message);
}
}
/**
* Basic implementation of the exception handling middleware.
*/
export const exceptionHandlingMiddleware: Middleware = {
async post(context: ResponseContext): Promise<Response | void> {
const response = context.response;
if (response.status >= 200 && response.status < 300) {
return response;
}
throw await RosettaRestClientFactory.getErrorFromFetchResponse(response);
},
};
/**
* Main class used to create Rosetta rest clients.
*
* These rest client would most likely be used for Rosetta e2e testing as this sdk brings server side dependencies (e.g. express) you may not want in a Rosetta client.
*
*/
export class RosettaRestClientFactory {
private readonly configuration: Configuration;
constructor(configs: RestClientFactoryParams) {
const fetchApi = configs.fetchApi || (typeof window !== 'undefined' && window.fetch.bind(window)) || fetch;
this.configuration = new Configuration({
basePath: configs.url,
fetchApi: fetchApi,
middleware: configs.middleware || [exceptionHandlingMiddleware],
});
}
public static async getErrorFromFetchResponse(error: Response): Promise<RestClientCallError> {
const statusCode = error?.status || 0;
const statusMessage = (error?.statusText || 'Unknown Error').toString();
const body = await error.text();
const getMessage = () => {
const defaultMessage = `${statusCode} - ${statusMessage}`;
try {
const modelError = ModelErrorFromJSON(JSON.parse(body));
return [modelError.code, modelError.message, modelError.description].join(' - ');
} catch (e) {
return defaultMessage;
}
};
const message = getMessage();
return new RestClientCallError(message, statusCode, statusMessage, body);
}
account(): AccountApiInterface {
return new AccountApi(this.configuration);
}
block(): BlockApiInterface {
return new BlockApi(this.configuration);
}
events(): EventsApiInterface {
return new EventsApi(this.configuration);
}
construction(): ConstructionApiInterface {
return new ConstructionApi(this.configuration);
}
call(): CallApiInterface {
return new CallApi(this.configuration);
}
mempool(): MempoolApiInterface {
return new MempoolApi(this.configuration);
}
network(): NetworkApiInterface {
return new NetworkApi(this.configuration);
}
search(): SearchApiInterface {
return new SearchApi(this.configuration);
}
}