Plugins

Creating Custom Plugins

Learn how to create custom plugins for URPC with entities, adapters, and complete implementations.

Plugin Structure

my-plugin/
├── src/
│   ├── entities/
│   │   └── user.ts
│   ├── adapters/
│   │   └── user-adapter.ts
│   ├── plugins/
│   │   └── index.ts
│   └── index.ts
├── package.json
└── tsconfig.json

Step-by-Step Guide

Define Your Entity

Entities define the structure of your data. Use decorators from @unilab/urpc-core to specify field types:

// src/entities/user.ts
import { Fields } from "@unilab/urpc-core";

export class UserEntity {
  @Fields.string({
    description: "The ID of this user",
  })
  id = "";

  @Fields.string({
    description: "The name of this user"
  })
  name = "";

  @Fields.string({
    description: "The email of this user"
  })
  email = "";

  @Fields.string({
    description: "The avatar of this user"
  })
  avatar = "";
}

Create Data Source Adapter

Adapters implement the BaseAdapter class to handle CRUD operations:

// src/adapters/user-adapter.ts
import {
  BaseAdapter,
  CreationArgs,
  FindManyArgs,
  FindOneArgs,
  URPCError,
  ErrorCodes,
} from "@unilab/urpc-core";
import {
  matchesWhere,
  performUpsert,
  processFindManyArgs,
} from "@unilab/urpc-adapters";
import { UserEntity } from "../entities/user";

// Mock data for demonstration
const userData = [
  {
    id: "1",
    name: "John Doe",
    email: "[email protected]",
    avatar: "https://example.com/avatar.png",
  },
  {
    id: "2",
    name: "Jane Smith",
    email: "[email protected]",
    avatar: "https://example.com/avatar2.png",
  },
];

export class UserAdapter extends BaseAdapter<UserEntity> {
  async findMany(args: FindManyArgs<UserEntity>, ctx?: OperationContext): Promise<UserEntity[]> {
    return processFindManyArgs(userData, args);
  }

  async findOne(args: FindOneArgs<UserEntity>, ctx?: OperationContext): Promise<UserEntity | null> {
    const item = userData.find((item) => matchesWhere(item, args.where));
    if (!item) {
      return null;
    }
    return item;
  }

  async create(args: CreationArgs<UserEntity>, ctx?: OperationContext): Promise<UserEntity> {
   const newUser = {
      ...args.data,
    };
    userData.push(newUser);
    return newUser;
  }
}

Create the Plugin Definition

// src/plugins/index.ts
import { Plugin } from "@unilab/urpc-core";
import { UserEntity } from "../entities/user";
import { UserAdapter } from "../adapters/user-adapter";

export const UserPlugin: Plugin = {
  entities: [UserEntity],
  adapters: [
    {
      source: "demo", 
      entity: "UserEntity",
      adapter: new UserAdapter()
    }
  ]
};