grubba:rpc

v0.7.4Published last year

RPC

What is this package?

Inspired on zodern:relay

This package provides functions for building E2E type-safe RPCs. The functions are:

  • crateMethod
  • createPublication

How to download it?

meteor npm i grubba-rpc
meteor npm i zod

or if you prefer using meteor package manager

meteor add grubba:rpc 
meteor npm i zod

How to use it?

1import {
2  ReturnMethod, // <- Type
3  ReturnSubscription, // <- Type
4  Config, // <- Type
5  SubscriptionCallbacks, // <- Type
6  createMethod, // <- function
7  createPublication // <- function
8} from 'grubba-rpc';

createMethod

1
2const test1 = createMethod('name', z.any(), () => 'str');
3const result = await test1();
4//    ˆ? is string and their value is 'str'

For semantics uses you can as well use the methods below with the same output as createMethod:

1const joinStr = createMutation(
2  'join',
3  z.object({ foo: z.string(), bar: z.string() }),
4  ({ foo, bar }) => foo + bar);
5const result = await joinStr({ foo: 'foo', bar: 'bar' });
6//    ˆ? is string and their value is 'foobar'
1const query = createQuery(
2  'query',
3  z.object({ _id: z.string() }),
4  async ({ _id }) => {
5    const someData = await DB.findOne(_id);
6    const otherData = await DB.find({ _id: { $ne: someData._id } }).fetchAsync();
7    return { someData, otherData };
8  });
9const result = await query({ _id: 'id' });
10//    ˆ? is string and their value is the item you was querying

example of use

createMethod accepts 4 arguments:

  • name: string
  • schema: ZodSchema (validator)
  • handler (optional): function that receives the arguments of the method and returns the result
  • config (optional): object with the following properties:
1type Config<S, T> = {
2  rateLimit?: {
3    interval: number,
4    limit: number
5  },
6  hooks?: {
7    onBeforeResolve?: Array<(raw: unknown, parsed: S,) => void>;
8    onAfterResolve?: Array<(raw: Maybe<T>, parsed: S, result: T) => void>;
9    onErrorResolve?: Array<(err: Meteor.Error | Error | unknown, raw: Maybe<T>, parsed: S) => void>;
10  }
11}

createPublication

1  const publication = createPublication('findRooms', z.object({ level: z.number() }), ({ level }) => Rooms.find({ level: level }));
2const result = publication({ level: 1 }, (rooms) => console.log(rooms));
3//                                            ˆ? subscription 
4

example of use

createPublication accepts 4 arguments:

  • name: string
  • schema: ZodSchema (validator)
  • handler (optional): function that is being published
  • config (optional): object with the following properties:

note that subscription returns the subscription handler the same way as Meteor.publish

1type Config<S, T> = {
2  rateLimit?: {
3    interval: number,
4    limit: number
5  },
6  hooks?: {
7    onBeforeResolve?: Array<(raw: unknown, parsed: S,) => void>;
8    onAfterResolve?: Array<(raw: Maybe<T>, parsed: S, result: T) => void>;
9    onErrorResolve?: Array<(err: Meteor.Error | Error | unknown, raw: Maybe<T>, parsed: S) => void>;
10  }
11}

Advanced usage

you can take advantage of the hooks to add custom logic to your methods and publications

1
2const fn = createMethod('name', z.any(), () => 'str', {
3  hooks: {
4    onBeforeResolve: [
5      (raw, parsed) => {
6        console.log('before resolve', raw, parsed);
7      }
8    ],
9    onAfterResolve: [
10      (raw, parsed, result) => {
11        console.log('after resolve', raw, parsed, result);
12      }
13    ],
14    onErrorResolve: [
15      (err, raw, parsed) => {
16        console.log('error resolve', err, raw, parsed);
17      }
18    ]
19  }
20});
21// valid ways as well
22fn.addErrorResolveHook((err, raw, parsed) => {
23  console.log('error resolve', err, raw, parsed);
24});
25fn.addBeforeResolveHook((raw, parsed) => {
26  console.log('before resolve', raw, parsed);
27});
28fn.addAfterResolveHook((raw, parsed, result) => {
29  console.log('after resolve', raw, parsed, result);
30});
31const result = await fn();

Using safe methods

check this example that illustrates this 'secure way' of using safe methods, as it is not bundled in the client

1
2import { createMethod } from 'grubba-rpc'
3import { z } from "zod";
4
5const DescriptionValidator = z.object({ description: z.string() });
6
7// tasks.mutations.ts
8// it expects the return type to be a void
9export const insert = createMethod('task.insert', DescriptionValidator).expect<void>();
10
11// tasks.mutations.js
12// If you are using javascript, you can use the following syntax
13export const insert = createMethod('task.insert', DescriptionValidator).expect(z.void());
14
15// ---------
16
17// tasks.methods.ts
18import { insert } from './tasks.mutations.ts'
19
20insertTask = ({ description }) => {
21  TasksCollection.insert({
22    description,
23    userId: Meteor.userId(),
24    createdAt: new Date(),
25  });
26};
27
28insert.setResolver(insertTask);
29
30// ---------
31
32
33// client.ts
34import { insert } from './tasks.mutations.ts'
35
36insert({ description: 'test' });
37//^? it return void and it will run
38// if resolver is not set it will throw an error
39

Experimental

createModule

1const Tasks = createModule('tasks', {insert, remove, setChecked}).build();
2const foo = createModule('foo')
3  .addMethod('bar', z.string(), () => 'bar' as const)
4  .addMethod('baz', z.string(), () => 'baz')
5  .addQuery('get', z.string(), () => 'get')
6  .build();
7const k = await foo.bar();
8//   ?^ 'bar'

There is as well the safeBuild method that will return a module and a setter for that module resolvers

1const [TaskModule, setTaskResolver]  = createModule('tasks', {insert, remove, setChecked}).safeBuild();
2setTaskResolver({ insert: ({description}) => 1 })
3setTaskResolver({
4  remove: ({taskId}) => {
5    console.log(taskId)
6  },
7  setChecked: ({taskId}) => {
8    console.log(taskId)
9  }
10})
11

I'm still solving the problem of how to type the resolvers.

Examples?

in the examples folder you can find a simple example of how to use this package it uses simpletasks as a base

for downloading it you can do the command below or just access this link

git clone https://github.com/Grubba27/meteor-rpc-template.git