الوثائقJavaScript الواجهات الخلفية

من إليسيا إلى Nexy

في Nexy، يتحول مسار Elysia إلى ملف Python ضمن src/routes/: تصبح مخططات t.Object نماذج Pydantic، ويصبح .group مجلدًا، و beforeHandle إلى dependencies.py، ويصبح عميل Eden المكتوب إجراءات مكتوبة.

يعرض كل قسم أدناه عادة إليسيا، ثم نفس الشيء في Nexy.

طريق

src/index.ts
import { Elysia } from "elysia"; new Elysia().get("/api/hello", () => ({ message: "Hello" })).listen(3000);

مسار الملف هو عنوان URL، واسم الوظيفة هو الطريقة:

src/routes/api/hello.py
async def GET():    return {"message": "Hello"}

المعلمات والاستعلام مع t

src/index.ts
import { Elysia, t } from "elysia"; new Elysia().get("/api/users/:id", ({ params, query }) => ({ id: params.id, fields: query.fields }), {  params: t.Object({ id: t.Numeric() }),  query: t.Object({ fields: t.Optional(t.String()) }),});

تنتقل الأنواع إلى المعلمات، و :id هو مقطع [id]:

src/routes/api/users/[id].py
async def GET(id: int, fields: str | None = None):    return {"id": id, "fields": fields}

جسم به t.Object

src/index.ts
app.post("/api/items", ({ body, set }) => {  set.status = 201;  return body;}, {  body: t.Object({ name: t.String(), price: t.Number({ exclusiveMinimum: 0 }) }),});
src/routes/api/items.py
from pydantic import BaseModel, Field from nexy.http import JSONResponse  class NewItem(BaseModel):    name: str    price: float = Field(gt=0)  async def POST(item: NewItem):    return JSONResponse(item.model_dump(), status_code=201)

response المخططات

src/index.ts
app.get("/api/me", () => ({ name: "Ada" }), {  response: t.Object({ name: t.String() }),});

نوع الإرجاع هو مخطط الاستجابة: يتم ترك الحقول غير المعلنة خارج الإجابة.

src/routes/api/me.py
from pydantic import BaseModel  class PublicUser(BaseModel):    name: str  async def GET() -> PublicUser:    return {"name": "Ada", "password_hash": "x"}

.group

src/index.ts
app.group("/admin", (admin) => admin.get("/stats", () => ({ users: 3 })));

المجلد هو المجموعة:

src/routes/admin/stats.py
async def GET():    return {"users": 3}

beforeHandle و guard

src/index.ts
app.group("/admin", (admin) =>  admin    .guard({      beforeHandle({ headers, error }) {        if (headers["x-role"] !== "admin") return error(403, "Admins only");      },    })    .get("/stats", () => ({ users: 3 })),);

A dependencies.py يحرس كل مسار لمجلده:

src/routes/admin/dependeency.py
from nexy.http import Header, HTTPException  def require_admin(x_role: str = Header("")) -> None:    if x_role != "admin":        raise HTTPException(status_code=403, detail="Admins only")  dependencies = [require_admin]

derive، decorate و state

src/index.ts
app  .derive(({ headers }) => ({ token: headers.authorization?.replace("Bearer ", "") }))  .get("/api/whoami", ({ token }) => ({ token }));

ما يضيفه derive إلى السياق هو التبعية التي يطلبها المعالج:

src/routes/api/whoami.py
from nexy.http import Depends, Header  def token(authorization: str = Header("")) -> str:    return authorization.removeprefix("Bearer ")  async def GET(token: str = Depends(token)):    return {"token": token}

decorate و state عبارة عن كائنات عادية على مستوى الوحدة النمطية، يتم استيرادها عند الحاجة إليها.

onAfterHandle و mapResponse

src/index.ts
app.onAfterHandle(({ set }) => {  set.headers["x-app"] = "demo";});
src/routes/middleware.py
from nexy.http import Request  async def middleware(request: Request, call_next):    response = await call_next(request)    response.headers["x-app"] = "demo"    return response

error() و onError

src/index.ts
app.get("/api/orders/:id", ({ params, error }) => {  if (Number(params.id) > 100) return error(404, "No such order");  return { id: params.id };});
src/routes/api/orders/[id].py
from nexy.http import HTTPException  async def GET(id: int):    if id > 100:        raise HTTPException(status_code=404, detail="No such order")    return {"id": id}

A notfound.nexy في المسارات يجيب الجذر على المتصفحات الموجودة على عنوان URL غير معروف.

ملفات تعريف الارتباط

src/index.ts
app.get("/api/theme", ({ cookie: { theme } }) => ({ theme: theme.value ?? "light" }));
src/routes/api/theme.py
from nexy.http import Cookie  async def GET(theme: str = Cookie("light")):    return {"theme": theme}

معاهدة عدن

src/index.ts
const app = new Elysia().post("/todos", ({ body }) => ({ title: body.title, done: false }), {  body: t.Object({ title: t.String() }),}); export type App = typeof app;
client.ts
import { treaty } from "@elysiajs/eden";import type { App } from "./src/index"; const api = treaty<App>("localhost:3000");const { data } = await api.todos.post({ title: "Write the docs" });

الإجراء هو الدالة Python وعميلها المكتوب في وقت واحد. يقوم Nexy بإنشاء أنواع TypeScript من التوقيع Python:

from pydantic import BaseModel from nexy.decorators import Action  class Todo(BaseModel):    title: str    done: bool = False  @Actionasync def add_todo(title: str) -> Todo:    return Todo(title=title)
src/components/AddTodo.tsx
import { useAction } from "@nexy/client";import { add_todo } from "@nexy/actions"; export function AddTodo() {  const { run, pending, data } = useAction(add_todo);  return (    <button disabled={pending} onClick={() => run({ title: "Write the docs" })}>      {data ? `Added ${data.title}` : "Add"}    </button>  );}

انظر الإجراءات.

الإضافات: cors، swagger، static

src/index.ts
import { cors } from "@elysiajs/cors";import { staticPlugin } from "@elysiajs/static";import { swagger } from "@elysiajs/swagger"; app.use(cors({ origin: "https://example.com" })).use(swagger()).use(staticPlugin());
إليسيا البرنامج المساعد نكسي
@elysiajs/cors useCORS = {"allow_origins": [...]} في nexyconfig.py
@elysiajs/swagger لا شيء: /docs قيد التشغيل افتراضيًا
@elysiajs/static لا شيء: public/ يتم تقديمه في /
nexyconfig.py
from nexy.core.models import NexyConfigModel  class NexyConfig(NexyConfigModel):    useCORS = {"allow_origins": ["https://example.com"]}

WebSockets

src/index.ts
app.ws("/ws/echo", {  message(ws, message) {    ws.send(message);  },});
src/routes/ws/echo.py
from fastapi import WebSocket  async def SOCKET(websocket: WebSocket):    await websocket.accept()    await websocket.send_text(await websocket.receive_text())

الاختبارات مع app.handle

اختبار/index.test.ts
import { describe, expect, it } from "bun:test"; it("says hello", async () => {  const response = await app.handle(new Request("http://localhost/api/hello"));  expect(await response.json()).toEqual({ message: "Hello" });});
الاختبارات/test_hello.py
from fastapi.testclient import TestClient from nexy.app import app  def test_hello():    assert TestClient(app).get("/api/hello").json() == {"message": "Hello"}

الجري

إليسيا نكسي
bun create elysia app nx new
bun dev nx dev
bun build --compile nx build، ثم nx start
bun test nx test

يعمل نيكسي على Python. تكون العقدة مطلوبة فقط عندما يحتوي المشروع على مكونات العميل: Vite يبنيها، ويعمل nx start بدونها.

الخطوات التالية

حرِّر على GitHub

Enter يفتح النتيجة، وEsc يغلق.