Apifly — это лёгкая и гибкая библиотека для организации клиент-серверного взаимодействия, поддерживающая удалённые вызовы процедур (RPC) и обмен состоянием. Она упрощает создание API, предоставляет встроенные возможности для кэширования, использования guard-функций, наблюдателей (watchers) и фильтров. Apifly помогает синхронизировать состояние между клиентом и сервером с минимальными усилиями и строгой типизацией.
Для начала необходимо определить тип состояния и процедур, которые будут использоваться в вашем приложении.
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;
}
>;
Пример настройки сервера на базе фреймворка 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);
Пример настройки клиента с указанием заголовков:
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 },
});
Пример использования клиента:
const [state, error] = await client.get();
console.log(state);
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
Этот модуль находится в активной разработке, и автор будет рад любым предложениям, исправлениям.