Учебник по RPC

В этом уроке я буду учить, как постепенно добавлять в вашу кодовую базу наш новый пакет grubba-rpc, чтобы узнать больше о том, что входит в этот пакет, вы можете посмотреть здесь.

Если вы хотите продолжить, вы можете использовать этот шаблон или получить окончательный исходный код здесь.

Когда начать?

Запустите установку пакетов:

meteor npm i grubba-rpc
meteor npm i zod

Затем выберите модуль, который вы хотите создать. Вы можете использовать старые методы, которые у вас уже есть.

Следите за новостями в api/tasks/tasks.methods.js

Вы можете перейти от чего-то вроде этого:

// in server.js
/**
 * Insert a task for the logged user.
 * @param {{ description: String }}
 * @throws Will throw an error if user is not logged in.
 */
const insertTask = ({ description }) => {
  checkLoggedIn();
  TasksCollection.insert({
    description,
    userId: Meteor.userId(),
    createdAt: new Date(),
  });
};
Meteor.methods({
  insertTask
})

Это имеет тот же эффект, что и это:

/**
 * Insert a task for the logged user.
 * @param {{ description: String }}
 * @throws Will throw an error if user is not logged in.
 */
const insertTask = ({ description }) => {
  checkLoggedIn();
  TasksCollection.insert({
    description,
    userId: Meteor.userId(),
    createdAt: new Date(),
  });
};
const insert = createMethod('insertTask', z.object({ description: z.string() }), insertTask);

Ключевое отличие заключается в клиенте:

До:

Meteor.call('insertTask', { description }, err => {
      if (err) {
        const errorMessage = err?.reason || 'Sorry, please try again.';
        actions.setStatus(errorMessage);
      } else {
        actions.resetForm();
      }
      actions.setSubmitting(false);
    });

С РПК:

Tasks.insert({ description })
  .then(() => {
    actions.resetForm();
  })
  .catch(err => {
    const errorMessage = err?.reason || 'Sorry, please try again.';
    actions.setStatus(errorMessage);
  })
  .finally(() => {
    actions.setSubmitting(false);
  })

Каковы преимущества?

Поскольку использование объекта JavaScript имеет некоторые преимущества, библиотека была написана на TypeScript, и поэтому, в дополнение к тому, что Zod помогает выполнять эти проверки, у нас есть полностью типизированные методы.

Крючки

У вас могут быть крючки. Например, вы можете отправлять электронное письмо каждый раз, когда кто-то добавляет новую задачу, когда кто-то удаляет задачу или когда что-то идет не так, переключаясь как выполненное.

import { insert, remove, setChecked } from "./mutations";
remove.addBeforeResolveHook((raw, parsed) => {
  console.log(parsed, 'email')
})
insert.addAfterResolveHook((raw, parsed, result) => {
  console.log(parsed, 'email')
})
setChecked.addErrorResolveHook((raw, parsed, error) => {
  console.log(error, 'email')
})

Это examples/simpletasks/common/tasks/mutations.hooks.ts

Этот пакет с шаблоном ловушки может помочь вам хорошо масштабировать многие приложения, потому что вы можете добавлять столько побочных эффектов контролируемым образом, сколько хотите.

Различные пакеты

Импорт ваших методов непосредственно из вашей папки common может попасть в клиентский и серверный код, что нежелательно для большинства разработчиков. Отличным решением является функция Method.setResolver, которую можно увидеть в api/tasks/tasks.methods.js.

// tasks/mutations.ts
const insert = createMethod('tasks.insert', TaskValidator).expect<void>()
const remove = createMethod('tasks.remove', IDValidator).expect<void>()
const setChecked = createMethod('tasks.setChecked', IDValidator).expect<void>()
// ....
Tasks.insert.setResolver(insertTask);
Tasks.remove.setResolver(removeTask);
Tasks.setChecked.setResolver(toggleTaskDone);

Только этот файл отправляется на сервер, а пользовательский интерфейс и общая папка отправляются клиенту. Поскольку на клиенте нет машинописного текста, от бэкэнд-кода не осталось и следа, и у вас есть этот потрясающий опыт разработчика.

Подписки

Еще один важный вопрос, который может возникнуть у людей, касается подписки. Почти так же, как методы, у нас есть и подписки. В examples/simpletasks/common/tasks/subscriptions.ts есть пример, где мы создаем публикацию следующим образом:

const tasksByUser = createPublication('tasks.byUser', z.any()).expect<Task>()

Вы можете использовать тот же способ, которым вы привыкли делать подписки:

import { TasksCollection } from './tasks.collection';
import { tasksByUser } from "../../common/tasks/subscriptions";
tasksByUser.setResolver(function () {
  return TasksCollection.find({ userId: this.userId });
})

Для внешнего интерфейса с использованием React у нас есть эта модель:

const isLoading = useSubscribe(tasksByUser.config.name);

subscriptionName.config.nameis для получения имени подписки, так как useSubscribe использует имя подписки для привязки значений

Хотите узнать больше?

Увидев, на что способен этот пакет, вам интересно попробовать его? Если да, вы можете проверить репозиторий, чтобы начать творить чудеса.