/ts-rpc

Primary LanguageJavaScriptMIT LicenseMIT

TS-Rpc

TS-Rpc is a Typescript-library of decorators for abstraction of transport layers and data transformation

Quick Example

import { IHttpClient, IRpcMethodConfig, IRpcServiceConfig, TSRpc, TSRpcError } from 'ts-rpc';
import { deserialize, JsonName, serialize } from 'tserialize';
import { guid } from 'some-guid-generator';

/* Example transport layer */
class JsonRpcTransportLayer implements IHttpClient {
    /* This is being set somewhere outside of this class */
    public static $http: ng.IHttpService;

    post(url: string, data: any, serviceConfig: any, methodConfig: any): any {
        const { $http } = JsonRpcTransportLayer;

        return new Promise((resolve, reject): void => {
            $http.post(url, data, this.requestConfig)
                .then(resolve)
                .catch(reject);
        });
    }
}

/* Example model */
class BaseRequest {
    @JsonName()
    secret: string;

    static fromServer = (obj: any): BaseRequest => deserialize(obj, BaseRequest);
    toServer = (): any => serialize(this);
}

interface IJsonRpcMethodConfig extends IRpcMethodConfig {
    method: string;
    responseModel?: { fromServer(rawData: object): any };
}

const servicePreprocessor = (request: any, serviceConfig: IRpcServiceConfig, methodConfig: IJsonRpcMethodConfig) => ({
    id: guid(),
    method: methodConfig.method,
    params: request
});
const servicePostprocessor = (request: any) => request.result;

export const JsonRpcService = TSRpc.makeClassDecorator({
    apiUrl: '/api/v1',
    httpClient: new JsonRpcTransportLayer()
});

const methodPreprocessor = (request?: any, config: IMethodConfig) => request ? request.toServer() : null;
const methodPostprocessor = (
        responseObject: Promise<any>,
        serviceConfig: IRpcServiceConfig,
        methodConfig: IJsonRpcMethodConfig
    ) => responseObject
        .catch(httpError => throw TSError.makeHttpError(httpError.status, httpError.statusText))
        .then(({ responseModel, result }) => responseModel ? responseModel.fromServer(result) : void 0);

export const JsonRpcMethod = TSRpc.makeMethodDecorator<{ toServer(): object }, IMethodConfig>(
    methodPreprocessor,
    methodPostprocessor
);

API

Class decorator factory

TSRpc.makeClassDecorator(config: IRpcServiceConfig)

Method decorator factory

TSRpc.makeMethodDecorator<TRequest, TPayload>(
    preprocessors: (request: TRequest) => any,
    postprocessors: (response: any, payload: TPayload) => any,
    transportFactory?: () => IHttpClient
)

Ideas

  • Add generics to adapter if possible