دستاویزاتکنٹرولر فریم ورک

NestJS سے Nexy تک

Nexy کا ماڈیولر راؤٹر NestJS کی شکل - کنٹرولرز، ماڈیولز، انجیکشن ایبل سروسز اور گارڈز کو Python میں رکھتا ہے، Pydantic کے ساتھ DTO کلاسز کی جگہ اور آپ کے لیے بنائے گئے OpenAPI دستاویزات۔

ذیل میں ہر سیکشن ایک NestJS عادت دکھاتا ہے، پھر Nexy میں وہی چیز۔ کیا NestJS کے پاس ہے اور Nexy میں کیا نہیں ہے وہ Nexy اور NestJS میں درج ہے۔

راؤٹر آن کر رہا ہے۔

src/main.ts
import { NestFactory } from "@nestjs/core";import { AppModule } from "./app.module"; const app = await NestFactory.create(AppModule);await app.listen(3000);

روٹ ماڈیول nexyconfig.py کا ایک فیلڈ ہے، اور nx dev اس کی خدمت کرتا ہے:

nexyconfig.py
from nexy.core.models import NexyConfigModel from src.apps.app_module import AppModule  class NexyConfig(NexyConfigModel):    useRouter = AppModule

ایک کنٹرولر

src/cats/cats.controller.ts
import { Controller, Get } from "@nestjs/common"; @Controller("cats")export class CatsController {  @Get()  findAll() {    return [{ name: "Tom" }];  }}

طریقہ کار کا نام HTTP فعل ہے:

src/apps/cats/cats_controller.py
from nexy.decorators import Controller  @Controller("/cats")class CatsController:    async def get(self) -> list[dict]:        return [{"name": "Tom"}]

ایک کنٹرولر کے پاس فی فعل ایک ہینڈلر ہوتا ہے۔ GET /cats اور GET /cats/:id دو کنٹرولر ہیں۔

روٹ کے پیرامیٹرز

src/cats/cat.controller.ts
@Controller("cats/:id")export class CatController {  @Get()  findOne(@Param("id", ParseIntPipe) id: number) {    return { id };  }}

@Param اور ParseIntPipe راستے میں ایک {id} بن جاتے ہیں اور ایک int تشریح:

src/apps/cats/cat_controller.py
from nexy.decorators import Controller  @Controller("/cats/{id}")class CatController:    async def get(self, id: int) -> dict:        return {"id": id}

استفسار کے پیرامیٹرز

src/cats/cats.controller.ts
@Get()findAll(@Query("limit", new DefaultValuePipe(10), ParseIntPipe) limit: number) {  return { limit };}

ایک استفسار پیرامیٹر ایک ڈیفالٹ کے ساتھ ایک پیرامیٹر ہے:

src/apps/search/search_controller.py
from nexy.decorators import Controller  @Controller("/search")class SearchController:    async def get(self, q: str = "", limit: int = 10) -> dict:        return {"q": q, "limit": limit}

ڈی ٹی اوز اور ValidationPipe

src/cats/create-cat.dto.ts
import { IsInt, IsString, Min } from "class-validator"; export class CreateCatDto {  @IsString()  name: string;   @IsInt()  @Min(0)  age: number;}
src/cats/cats.controller.ts
@Post()create(@Body() dto: CreateCatDto) {  return dto;}

ڈی ٹی او ایک Pydantic ماڈل ہے۔ اس کی توثیق ہمیشہ کی جاتی ہے، اور خراب جسم جواب دیتا ہے 422:

src/apps/cats/cats_dto.py
from pydantic import BaseModel, Field  class CreateCat(BaseModel):    name: str    age: int = Field(ge=0)
src/apps/cats/new_cat_controller.py
from nexy.decorators import Controller from .cats_dto import CreateCat  @Controller("/cats/new")class NewCatController:    async def post(self, body: CreateCat) -> CreateCat:        return body

فراہم کنندہ اور کنسٹرکٹر انجیکشن

src/cats/cats.service.ts
@Injectable()export class CatsService {  findAll() {    return [{ name: "Tom" }];  }} @Controller("cats")export class CatsController {  constructor(private readonly cats: CatsService) {}   @Get()  findAll() {    return this.cats.findAll();  }}

وہی دو ڈیکوریٹر؛ __init__ کی قسم کی تشریح کنٹینر کو بتاتی ہے کہ کیا انجیکشن لگانا ہے:

src/apps/cats/cats_service.py
from nexy.decorators import Injectable  @Injectable()class CatsService:    def find_all(self) -> list[dict]:        return [{"name": "Tom"}]
src/apps/cats/cats_controller.py
from nexy.decorators import Controller from .cats_service import CatsService  @Controller("/cats")class CatsController:    def __init__(self, cats: CatsService) -> None:        self.cats = cats     async def get(self) -> list[dict]:        return self.cats.find_all()

دائرہ کار

src/cats/request-context.ts
@Injectable({ scope: Scope.REQUEST })export class RequestContext {}
src/apps/cats/request_context.py
from nexy.decorators import Injectable, Scope  @Injectable(scope=Scope.REQUEST)class RequestContext: ...

Scope.SINGLETON پہلے سے طے شدہ ہے، جیسا کہ NestJS میں ہے، اور Scope.TRANSIENT فی انجیکشن ایک نئی مثال دیتا ہے۔

ماڈیولز

src/cats/cats.module.ts
@Module({  controllers: [CatsController, CatController],  providers: [CatsService],  exports: [CatsService],})export class CatsModule {} @Module({ imports: [CatsModule] })export class AppModule {}

چار صفیں چار طبقاتی صفات ہیں:

src/apps/cats/cats_module.py
from nexy.decorators import Module from .cat_controller import CatControllerfrom .cats_controller import CatsControllerfrom .cats_service import CatsServicefrom .new_cat_controller import NewCatController  @Module()class CatsModule:    controllers = [CatsController, CatController, NewCatController]    providers = [CatsService]    exports = [CatsService]
src/apps/app_module.py
from nexy.decorators import Module from .admin.admin_controller import AdminControllerfrom .cats.cats_module import CatsModulefrom .search.search_controller import SearchController  @Module()class AppModule:    controllers = [SearchController, AdminController]    imports = [CatsModule]

@Module(prefix="/api") ماڈیول کے ہر کنٹرولر کا سابقہ لگاتا ہے، جیسے RouterModule یا setGlobalPrefix("api")۔

گارڈز

src/auth/token.guard.ts
@Injectable()export class TokenGuard implements CanActivate {  canActivate(context: ExecutionContext): boolean {    const request = context.switchToHttp().getRequest();    return request.headers["x-token"] === "secret";  }} @Controller("admin")@UseGuards(TokenGuard)export class AdminController {}

گارڈ ایک ایسا فنکشن ہے جو اس وقت اٹھاتا ہے جب درخواست جاری نہ ہو:

src/apps/admin/admin_controller.py
from fastapi import Header, HTTPException from nexy.decorators import Controller, UseGuard  def require_token(x_token: str = Header("")) -> None:    if x_token != "secret":        raise HTTPException(status_code=403, detail="Forbidden")  @Controller("/admin")@UseGuard(require_token)class AdminController:    async def get(self) -> dict:        return {"ok": True}

مستثنیات

throw new NotFoundException("No such cat");throw new ForbiddenException();
from fastapi import HTTPException from nexy import forbidden raise HTTPException(status_code=404, detail="No such cat")forbidden()

دونوں جوابات اسٹیٹس کوڈ کے ساتھ {"detail": ...} دیتے ہیں، جیسا کہ NestJS جوابات {"message": ...}۔

مڈل ویئر اور انٹرسیپٹرز

src/logger.middleware.ts
@Injectable()export class AppHeaderMiddleware implements NestMiddleware {  use(req: Request, res: Response, next: NextFunction) {    res.setHeader("X-App", "demo");    next();  }}

ASGI مڈل ویئر کلاس، جو nexyconfig.py میں درج ہے، ہر درخواست کو سمیٹتی ہے:

src/app_header.py
from starlette.middleware.base import BaseHTTPMiddleware  class AppHeaderMiddleware(BaseHTTPMiddleware):    async def dispatch(self, request, call_next):        response = await call_next(request)        response.headers["x-app"] = "demo"        return response
nexyconfig.py
from nexy.core.models import NexyConfigModel from src.app_header import AppHeaderMiddlewarefrom src.apps.app_module import AppModule  class NexyConfig(NexyConfigModel):    useRouter = AppModule    useMiddlewares = [AppHeaderMiddleware]

ایک انٹرسیپٹر جو ردعمل کا نقشہ بناتا ہے وہی مڈل ویئر ہے، call_next کے بعد کوڈ کے ساتھ۔

اکڑ

@ApiOperation({ summary: "List cats" })@ApiResponse({ status: 200 })@Get()findAll() {}

کوئی SwaggerModule.setup نہیں ہے: ہر کنٹرولر /docs پر پیش کردہ اسکیما میں ہے۔ ڈیکوریٹر صرف وہی شامل کرتے ہیں جو دستخط نہیں کہتے ہیں:

src/apps/docs/documented_controller.py
from nexy.decorators import Controller, UseResponse, UseRoute  @Controller("/documented")class DocumentedController:    @UseRoute(summary="List cats", tags=["cats"])    @UseResponse(status_code=200)    async def get(self) -> list[dict]:        return []

WebSocket گیٹ ویز

src/events.gateway.ts
@WebSocketGateway()export class EventsGateway {  @SubscribeMessage("echo")  echo(@MessageBody() data: string) {    return data;  }}

ایک SOCKET طریقہ اپنے کنٹرولر کے راستے پر ایک WebSocket کو کھولتا ہے:

src/apps/ws/echo_controller.py
from fastapi import WebSocket from nexy.decorators import Controller  @Controller("/ws/echo")class EchoController:    async def SOCKET(self, websocket: WebSocket) -> None:        await websocket.accept()        await websocket.send_text(await websocket.receive_text())

ہر کنٹرولر کی طرح، یہ ایک بار جواب دیتا ہے جب ماڈیول اسے controllers میں درج کرتا ہے۔ کنٹرولر کا راستہ سلیش کے ساتھ ختم ہوتا ہے: /ws/echo/ سے جڑیں، کیونکہ WebSocket کو HTTP درخواست کی طرح ری ڈائریکٹ نہیں کیا جاتا ہے۔

ConfigModule

@Module({ imports: [ConfigModule.forRoot()] })export class AppModule {} constructor(private config: ConfigService) {}this.config.get("DATABASE_URL");

سیٹنگز ایک Pydantic ماڈل یا سادہ ماحول کے متغیرات ہیں، کسی بھی فراہم کنندہ کی طرح انجیکشن:

src/apps/settings.py
import os from nexy.decorators import Injectable  @Injectable()class Settings:    def __init__(self) -> None:        self.database_url = os.getenv("DATABASE_URL", "sqlite:///dev.db")

ٹیسٹ

src/cats/cats.controller.spec.ts
const moduleRef = await Test.createTestingModule({ imports: [AppModule] }).compile();const app = moduleRef.createNestApplication();await app.init();await request(app.getHttpServer()).get("/cats").expect(200);
tests/test_cats.py
from fastapi.testclient import TestClient from nexy.app import app  def test_cats():    assert TestClient(app).get("/cats").json() == [{"name": "Tom"}]

کسی سروس کو ٹیسٹ میں تبدیل کرنے کے لیے، Depends کے ذریعے اس پر انحصار کریں اور FastAPI کے app.dependency_overrides کا استعمال کریں: دیکھیں Nexy اور NestJS۔

چل رہا ہے۔

NestJS نیکسی
nest new nx new، پھر ماڈیولر راؤٹر چنیں۔
npm run start:dev nx dev
npm run build && npm run start:prod nx build، پھر nx start
npm test nx test
nest generate controller ایک نیا *_controller.py، اس کے ماڈیول میں شامل کیا گیا۔

یا کلاسز کے بجائے فائلز

ایک NestJS ایپ جو زیادہ تر CRUD ہے فائل پر مبنی راؤٹر میں بھی جا سکتی ہے، جہاں فولڈر راستہ ہے اور مطابقت پذیر رکھنے کے لیے کوئی ماڈیول نہیں ہیں:

src/routes/cats/[id].py
async def GET(id: int):    return {"id": id}

دیکھیں روٹر کا انتخاب کریں۔

اگلے اقدامات

GitHub پر ترمیم کریں

Enter نتیجہ کھولتا ہے، Esc بند کرتا ہے۔