npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@artempoletsky/easyrpc

v1.4.0

Published

API library

Downloads

13

Readme

About The Project

EasyRPC is a library for implementing Remote Procedure Call pattern in Typescript.

Key features:

  • Zero learning curve. If you know how to use Javascript asynchronous functions you know how to use this library.
  • Write methods on the server and call them on the client like AJAX doesn't even exist.
  • Minimum boilerplate.
  • Convenient error handling.
  • Supports templates for error messages and i18n.

It uses zod for data validation.

EasyRPC is framework agnostic but it has some useful methods for working with Next.js and Mantine.

Installation

npm install --save @artempoletsky/easyrpc

Basic usage

Thess examples are provided for a Next.js route

First create a new directory for a new Next API route. Create 2 files inside it: schemas.ts and route.ts.

schemas.ts contains validation rules for your API methods.

It's recommended to create it if you want to use zod for validation on the client. This way you can use same validation rules on both the client and the server.

// schemas.ts

import z from "zod";

//myMethod is exact name of your method
export const myMethod = z.object({
  num: z.number(),
  num: z.string(),
  array: z.array(z.number()),
  etc: z.any(),
});

// the naming prefix `A` stands for Argument. You can use your own naming conventions.
export type AMyMethod = z.infer<typeof myMethod>;

// ... export other methods this way

Next.js route:

// route.ts

import { NextResponse } from "next/server";
import validate, { NextPOST, ResponseError } from "@artempoletsky/easyrpc";
import * as schemas from "./schemas";
import type { AMyMethod } from "./schemas";

//implement your method 
async function myMethod({ num, str, array, etc }: AMyMethod){
  // zod will ensure that all args are valid here

  // send 400 error to the client
  if (false) throw new ResponseError("Bad request");

  // send 400 error to the client and tell that a specific form field caused it
  if (false) throw new ResponseError("fieldName", "Bad field");

  if (false) throw new Error("Something got wrong"); // 500 error

  return "Hello RPC!"; // send this as a responce to the client
}

// export the method signature as a type for using on the client
// the naming prefix `F` stands for Function
export type FMyMethod = typeof myMethod;

//  the shortcut `NextPOST` function that creates a POST function for you
export const POST = NextPOST(NextResponse, schemas, {
  myMethod,
});

Also you can implement the POST method yourself if you want a more fine tuned behavior. Use validate function for that.


import validate from "@artempoletsky/easyrpc";

// next.js API route implementation
export async function POST(req: NextRequest) {
  // get method and arguments from the request
  let { method, args } = await req.json();


  let [result, statusObject] = await validate(
    { // pass the arguments and the method name
      method, // "myMethod"
      args, // args is TMyMethod if valid
    },
    schemas,
    {
      myMethod, // pass here all of your methods 
    }
  );
  // `result`` is "Hello RPC!" if args is valid
  // `statusObject` is { status: 200 } if args is valid
  // if the method name doesn't exist or `args` is invalid `validate` will return 400 and the error message
  return NextResponse.json(result, statusObject);
}

The client code:

// some_client_code.tsx

import { getAPIMethod } from "@artempoletsky/easyrpc/client";
import type { FMyMethod } from "../path/to/your/api/route";

const myMethod = getAPIMethod<FMyMethod>("http_path/to/your_route", "myMethod");

export default function Page() {
  const [setRequestError, mainErrorMessage] = useErrorResponse();

  function onClick(){
    //clear errors before request
    setRequestError();
    //call it with the signature defined on the server
    myMethod({
      num: 1,
      str: "Hello!",
      array: [1, 2, 3],
      etc: null,
    })
      .then(console.log) // prints "Hello RPC!" to the browser's console
      .catch(setRequestError); // catch errors
  }
  return (
   <button onClick={onClick}>Call my method!</button>
   <div>{mainErrorMessage}</div>
  )
}

When throwng ResponseError you can customize the error code, error fields and send custom info to the client.

  if (false) throw new ResponseError({
    message: "Bad request",
    statusCode: 403,

    invalidFields: {
      num: {
        message: "Invalid",
        args: []
      },
      str: {
        message: "Invalid",
        args: []
      }
    },

        payload: {
      some: "custom info",
    },
  });

Using with @mantine/form



import { getAPIMethod } from "@artempoletsky/easyrpc/client";
import { useForm } from "@mantine/form";

import type { FAuthorize } from "../path/to/your/api/route";

// import your zod schemas for Mantine form
import { AAuthorize, authorize as ZAuthorize } from "../path/to/your/api/schemas";

const authorize = getAPIMethod<FAuthorize>("http_path/to/your_route", "authorize");

export default function Page() {
  const form = useForm<AAuthorize>({
    initialValues: {
      userName: "",
      password: "",
    },
    validate: zodResolver(ZAuthorize), // validates on the client
  });

  const [setRequestError, mainErrorMessage] = useErrorResponse(form); // pass a Mantine form

  function onAutorize({ userName, password }: AAuthorize) {
    setRequestError();
    authorize({ userName, password })
      .then(() => {
        // reloading the page
        window.location.href += "";
      })
      .catch(setRequestError);
  }
  
  return (
    <form onSubmit={form.onSubmit(onAutorize)}>
      <TextInput
        {...form.getInputProps("userName")} // the magic will handle all field errors for you
        placeholder="username"
      />
      <TextInput
        {...form.getInputProps("password")} // the magic will handle all field errors for you
        placeholder="password" type="password" />
      <Button type="submit">Login</Button>
      <div>{mainErrorMessage}</div>
    </form>
  )
}