Security News
38% of CISOs Fear They’re Not Moving Fast Enough on AI
CISOs are racing to adopt AI for cybersecurity, but hurdles in budgets and governance may leave some falling behind in the fight against cyber threats.
@pawsteam/ts-jsonrpc-server
Advanced tools
A framework for easily building JSONRPC simple servers in TS
This is a very simple & straight forward way of creating JSONRPC serices. It can also emit events that other services can subscribe to, in order to create an API event-based infrastructure.
For MacOS Catalina, please follow this link
All the rest, npm install @pawsteam/ts-jsonrpc-server
.
@AppConfigDecorator({
port: 2000,
services: [SomeService],
genericValidators: [
new HeaderExistsValidator('content-type'),
new HeaderValueContainsValidator('user-agent', 'Mozilla/5.0')
]
})
class AppMain {
}
@ServiceDecorator({path: '/hotels'})
class HotelsService {
listHotels(): Promise<any> {
return new Promise((resolve, reject) => {
// fetch data.then((data) => {
resolve(data);
// })
})
}
}
Later, when running this app, you can make a JSONRPC request to the methods exposed by this endpoint:
request({
method: 'post',
url: 'http://localhost:2000/hotels'
json: {
id: Math.round(Math.random() * 1000),
jsonrpc: '2.0',
method: 'listHotels',
params: {}
}
}, (error, response, body) => {
expect(body).toMatchObject({
id: ...,
jsonrpc: '2.0',
result: {data}
})
})
The framework is aimed at making life easier when writing JSON-RPC servers. It is Promise-based, so everything returns a promise, with very few exceptions (validators). It is based on stages/hooks in the life of a request:
The life stages of a request can be intercepted with special classes that must implement specific interfaces.
They check the request for required data and types. It's a place to define what parameters are needed for a method to be called.
Any number of Input Validators can be assigned for one method. Generic ones as well;
#### Generic validators
Generic validators are set on the app level, and they will be triggered on all requests for this app.
```typescript
@AppConfigDecorator({
port: 2000,
services: [SomeService],
genericValidators: [
new HeaderExistsValidator('content-type'),
new HeaderValueContainsValidator('user-agent', 'Mozilla/5.0')
]
})
export class AppMain {
}
export class HeaderExistsValidator implements ValidatorInterface {
headerName: string;
constructor(headerName: string) {
this.headerName = headerName;
}
validate(params: any, request): boolean {
return !!request.headers[this.headerName];
}
}
```
The input validators implement ValidatorInterface and return a boolean value.
@ValidatorDecorator(new HeaderExistsValidator('x-content-type'))
private method1() {
return Promise.resolve(true);
}
Similarily to the example above, here we define the validator for this particular method.
They transform the request data into objects that are passed to the methods. Any number of input transformer can exist per method.
The transformer returns a promise of one parameter type.
The order of validators will give the order of parameters in the method call.
The transformers implement the TransformerInterface and return a Promise to the type of object they are for.
export class BucketTransformer implements TransformerInterface {
/**
* The ParsedRpcObjectType is an object created from the body of the request, parsed,
* and put into the form of a JSONRPC object:
* {
* id: <id>,
* method: <methodname>,
* jsonrpc: '2.0',
* params: {...}
* }
*/
transform(request: IncomingMessage, jsonrpcObj: ParsedRpcObjectType): Promise<BucketType> {
const newBucket = new BucketType(jsonrpcObj.params.path);
return Promise.resolve(newBucket);
}
}
The reason this method needs to return a promise is because we might need to fetch additional data in order to create the object. For instance, we might need to query a DB.
Validation can also be done in the transformer. If the transformer rejects the promise or throws, the transformation is interpreted as failed, so validation failed.
To use a transformer, you simply instantiate a new instance of your transformer:
@TransformerDecorator(new CarTransformer())
@TransformerDecorator(new EngineTransformer())
method3(car: CarType, engine: EngineType, request: IncomingMessage, response: ServerResponse) {
return Promise.resolve(car.wheels * engine.power);
}
This is where the app logic lives
It must also return a promise of any type of object, this object will be serialized/processed if needed, then replied to the user
```
@ValidatorDecorator(new BucketValidator())
@TransformerDecorator(new BucketTransformer())
createBucket(bucket: BucketType, context: RequestContextType): Promise<any> {
return Promise.resolve({created: bucket.path});
}
```
This is where you can decide what exactly ends up in the response. Everything in the response can be changed at this step.
The serializers must implement SerializerInterface. They must return an object of type JsonRpcResponseType.
// example of serializer - removes all keys that contain the string 'test' from the response.
class RemoveTestsSerializer implements SerializerInterface {
serialize(serializeParams: SerializerParameterType): JsonRpcResponseType {
for (const key in serializeParams.objectToBeReturned) {
if (key.indexOf('test') !== -1) {
delete serializeParams.objectToBeReturned[key];
}
}
return serializeParams.objectToBeReturned;
}
}
@SerializerDecorator(new RemoveTestsSerializer())
method4(req, resp) {
console.log('METHOD 4 called');
return Promise.resolve({test2: 'test', ihaveatesttorun: 'Ihaveatesttorun', someKey: 16});
}
One of the core functionalities of the framework is to make sure that methods can asynchronously emit events, on API calls.
The messaging paradigm used is PUB/SUB. This means that the events are published and lost if no subscribers are present. On the other hand, if multiple subscribers subscribe to the same event, they will all receive the same events.
Easiest way to include the events functionality is through a simple decorator.
// step 1 - define the connection & transport
// for now only Rabbit transporters are allowed
@AppConfigDecorator({
messaging: {
serviceName: 'NewService',
host: 'localhost'
},
port: 2000,
services: [NewService]
})
class app {
}
// step 2 - in the service method, mention the decorator
@ServiceDecorator({
path: '/newpath',
serializer: new RemoveTestsSerializer()
})
export class NewService implements ServiceInterface {
EventEmitterDecorator()
method2() {
return Promise.resolve({sum: 8, product: 15});
}
}
By default, this will render a message similar to this
{
eventType: 'method2',
eventParams: {
sum: 8,
product: 15
}
}
Alternatively, you can also select and change the keys that will be published in the event, by passing a json parameter to the EventEmitterDecorator()
@EventEmitterDecorator({
sum: '', // an empty string means the key's name will be used in the event keys
prod: 'product'
})
method3() {
return Promise.resolve({sum: 5+3, prod: 5*3, excluded: 5-3});
}
The above example would send a message on the queue which looks like this:
{
sum: 8,
product: 15
}
Notice how the returned keys are sum, prod and excluded, and the event only has sum and product.
FAQs
A framework for easily building JSONRPC simple servers in TS
The npm package @pawsteam/ts-jsonrpc-server receives a total of 1 weekly downloads. As such, @pawsteam/ts-jsonrpc-server popularity was classified as not popular.
We found that @pawsteam/ts-jsonrpc-server demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
CISOs are racing to adopt AI for cybersecurity, but hurdles in budgets and governance may leave some falling behind in the fight against cyber threats.
Research
Security News
Socket researchers uncovered a backdoored typosquat of BoltDB in the Go ecosystem, exploiting Go Module Proxy caching to persist undetected for years.
Security News
Company News
Socket is joining TC54 to help develop standards for software supply chain security, contributing to the evolution of SBOMs, CycloneDX, and Package URL specifications.