RPC
What is this package?
This package provides functions for building E2E type-safe RPCs. they are:
- crateMethod
- createPublication
Hot to download it?
meteor add grubba:rpc meteor npm i 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'
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// --------- 12 13// tasks.methods.ts 14import { insert } from './tasks.mutations.ts' 15insertTask = ({ description }) => { 16 TasksCollection.insert({ 17 description, 18 userId: Meteor.userId(), 19 createdAt: new Date(), 20 }); 21}; 22 23insert.setResolver(insertTask); 24 25// --------- 26 27 28// client.ts 29import { insert } from './tasks.mutations.ts' 30insert({ description: 'test' }); 31//^? it return void and it will run 32// if resolver is not set it will throw an error 33
Examples?
in the examples folder you can find a simple example of how to use this package it uses simpletasks as a base