Skip to content

vseplet/apifly

Repository files navigation

Apifly

Apifly

Apifly JSR Badge

Apifly - лёгкая и гибкая библиотека для организации клиент-серверного взаимодействия, поддерживающая RPC и обмен состоянием с возможностью кэширования, фильтров, guards и watchers.

Содержание:

Описание

Apifly — это лёгкая и гибкая библиотека для организации клиент-серверного взаимодействия, поддерживающая удалённые вызовы процедур (RPC) и обмен состоянием. Она упрощает создание API, предоставляет встроенные возможности для кэширования, использования guard-функций, наблюдателей (watchers) и фильтров. Apifly помогает синхронизировать состояние между клиентом и сервером с минимальными усилиями и строгой типизацией.

Быстрый старт

1. Определение состояния и процедур

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

import { ApiflyDefinition } from "@vseplet/apifly/types";

export type MyApiflyDefinition = ApiflyDefinition<
  {
    counter: number;
    message: string;
    user: {
      tg_id: string;
    };
  },
  {
    incrementCounter: {
      args: [number];
      returns: string;
    };
    resetCounter: {
      args: [];
      returns: string;
    };
    getMessage: {
      args: [];
      returns: string;
    };
  },
  {
    userId: string;
  }
>;

2. Настройка сервера

Пример настройки сервера на базе фреймворка Hono и использования Apifly для управления состоянием:

import apifly from "@vseplet/apifly";
import type { ApiflyDefinition } from "@vseplet/apifly/types.ts";
import { Hono } from "jsr:@hono/hono";

type MyApiflyDefinition = ApiflyDefinition<
  {
    counter: number;
    message: string;
    user: {
      tg_id: string;
    };
  },
  {
    incrementCounter: {
      args: [number];
      returns: string;
    };
    resetCounter: {
      args: [];
      returns: string;
    };
    getMessage: {
      args: [];
      returns: string;
    };
  },
  {
    userId: string;
  }
>;

let database: Record<string, {
  counter: number;
  message: string;
  user: {
    tg_id: string;
  };
}> = {};

// Функции для симуляции чтения/записи данных
async function readFromDatabase(userId: string) {
  console.log(`Reading state for userId: ${userId}`);
  await new Promise((resolve) => setTimeout(resolve, 2000));

  if (!database[userId]) {
    database[userId] = {
      counter: 0,
      message: "Initial message",
      user: { tg_id: userId },
    };
  }
  return database[userId];
}

async function writeToDatabase(userId: string, newState: any) {
  console.log(`Writing state for userId: ${userId}`);
  database[userId] = newState;
}

const apiflyManager = new apifly.manager<MyApiflyDefinition>(
  true,
  4000,
  "userId",
)
  .load(async (args) => await readFromDatabase(args.userId))
  .unload(async (args) => await writeToDatabase(args.userId, args.state))
  .procedure("incrementCounter", async (args, state) => {
    state.counter += args[0];
    return `Counter incremented by ${args[0]}, new value: ${state.counter}`;
  })
  .procedure("resetCounter", async (args, state) => {
    state.counter = 0;
    return "Counter reset to 0";
  })
  .procedure("getMessage", async (args, state) => state.message)
  .guard("counter", ({ newValue }) => newValue >= 0)
  .watcher("counter", async ({ newValue, currentValue, userId }) => {
    console.log(
      `Watcher: Counter changed from ${currentValue} to ${newValue} for user ${userId}`,
    );
  })
  .filter("message", ({ currentValue }) => !currentValue.includes("secret"));

const apiflyServer = new apifly.server<MyApiflyDefinition>(
  apiflyManager,
  "/api/apifly",
  {
    userId: "X-User-ID",
  },
);

const server = new Hono();
apiflyServer.registerRoutes(server);

console.log("Server is running");
Deno.serve(server.fetch);

3. Создание клиента

Пример настройки клиента с указанием заголовков:

import apifly from "@vseplet/apifly";
import type { MyApiflyDefinition } from "./MyApiflyDefinition.type.ts";

export const client = new apifly.client<MyApiflyDefinition>({
  baseURL: "https://apiflyservertesting.deno.dev/api/apifly",
  headers: {
    "X-User-ID": "user10",
  },
  limiter: { unlimited: true },
});

Пример использования клиента:

GET запрос:

const [state, error] = await client.get();
console.log(state);

PATCH запрос:

const patchedState = await client.patch({
  message: "Updated message!",
});
console.log(patchedState);

Вызов процедуры:

const [result, error] = await client.call("incrementCounter", [5]);
console.log(result);

Пример работы с кэшем

const [state, error] = await client.get();

Установка

Для установки используйте JSR:

jsr install @vseplet/apifly

Поддержка и обратная связь

Этот модуль находится в активной разработке, и автор будет рад любым предложениям, исправлениям.

About

Cross runtime state sharing library on HTTP

Resources

License

Stars

Watchers

Forks