--- name: Dext Framework Patterns description: Architectural patterns, Entity ORM, Minimal APIs and dependency injection for projects created with Dext Framework (cesarliws/dext). --- # Dext Framework Patterns (Delphi) The **Dext Framework** is a complete ecosystem for Delphi, directly inspired by **ASP.NET Core** and **Spring Boot**. It is intended for high-performance corporate development. Unlike Horse or DMVC, Dext embraces Dependency Injection, Minimal APIs with automatic model binding and has its own Entity ORM (`Dext.Entity`). This manual provides the conventions that must be followed by the AI ​​when coding with Dext. **Important Note:** Dext Framework is **not** short for DevExpress/DevExtreme visual components, but rather the backend project (https://github.com/cesarliws/dext). ## Core Principles 1. **Minimal Routing (Minimal APIs):** Do not use traditional MVC Controllers unless necessary. Use functional routing syntax (`MapGet`, `MapPost`). 2. **Auto Model Binding:** Get JSON body not via strings and partial conversions, but by delegating strong typing to anonymous route parameters (`function(Dto: MyDto): IResult`). 3. **Integrated DI Container:** All interface dependencies must be resolved via `App.Services` (Injection). Do not use manual factories. 4. **Smart ORM (Dext.Entity):** Never concatenate SQL. --- ## 1. WebApp Lifecycle and DI Bootstrap of a Dext API occurs by registering services in the same route pipeline. ```pascal program MyAPI; uses Dext.Web, Services.Interfaces, Services.Implementations; begin var App := WebApplication; var Builder := App.Builder; // 1. Registro de Serviços de Injeção de Dependências App.Services.AddSingleton; App.Services.AddScoped; // 2. Mapeamento de Rotas Builder.MapGet('/health', function: IResult begin Result := Results.Ok('{"status": "ok"}'); end); // 3. Start App.Run(8080); end. ``` --- ## 2. Minimal APIs & Model Binding The preferred way to build REST APIs with Dext is using typed anonymous delegates, with DI dependencies passed in the final arguments. ### Create user (Post + DTO Body + Auth) ```pascal type TCreateUserDto = record Name: string; Age: Integer; end; // 'Dto' é populado via JSON do corpo da requisição automaticamente. // 'Database' é injetado via DI. Builder.MapPost('/users', function(Dto: TCreateUserDto; Database: IDatabaseService): IResult begin if Dto.Name.IsEmpty then Exit(Results.BadRequest('Name is required')); Database.SaveUser(Dto.Name, Dto.Age); Result := Results.Created('/users/new', 'User Created'); end); ``` ### Path Params & Query ```pascal // Roteamento path-based tipado (Route parameter Binding) Builder.MapGet('/orders/{id}', function(Id: Integer): IResult begin var Order := FindOrder(Id); if Order = nil then Result := Results.NotFound else Result := Results.Ok(Order); end); ``` --- ## 3. Dext.Entity (ORM & Smart Properties) Database mapping with Dext is focused on strongly typed query building and "Code First" Classes. ### LINQ-Like Queries Avoid using complex RTTI or native ADOTables if you are on Dext. Deliver results in typed Collections (`IList`). ```pascal uses Dext.Entity; // P é a representaction da Smart Property para a classe de contexto var Products := DbContext.Products .Where((P.Price > 100) and (P.Stock > 0)) // 'and' bitwise/Smart property syntax .OrderBy(P.Name) .Take(10) .ToList; ``` ### Understanding "Mass Update" via Dext.Entity With Dext ORM, Updates can run in the database without pulling data into memory (as done in modern Entity Framework Core): ```pascal DbContext.Orders .Where(O.Status = 'Pending') .Update .Execute; ``` --- ## 4. Returns (IResult) Always return `IResult`-based implementations on endpoints using the `Results` factory. - `Results.Ok( MeuRecord )` -> Status 200 + Automatically Serializes into JSON. - `Results.Created('/rota', 'Msg')` -> Status 201 + Header "Location". - `Results.NotFound` -> Status 404. - `Results.BadRequest('Msg')` -> Status 400 bad request error. --- ## 5. Dext.Net Async Tasks and Resilience (TAsyncTask) Dext includes more modern promises/tasks primitives than the pure `TTask` originals of Delphi. ```pascal uses Dext.Core.Tasks; // Usar Task Flow da biblioteca central TAsyncTask.Run( function: TUserProfile begin Result := ExternalService.Call(); end) .OnComplete( // Callback chamado no contexto Sincrono/Main thread. procedure(Profile: TUserProfile) begin ShowVclMessage(Profile.Name); end) .OnException( procedure(Ex: Exception) begin LogError(Ex.Message); end) .Start; ``` --- ## Review Checklist (Dext Framework) - **Fluent routes?** Does the application use `Builder.MapGet`/`MapPost` with implicit binding instead of manual request manipulation and pure Body parse for complex json objects? - **Has the DI container been powered?** Are instances being passed to constructors/routers through `App.Services`? - **No Filter Strings in Data Modules?** Did you use expressive Smart Properties (`.Where(E.Price > 100)`) instead of query concat? - **Are returns based on records and POLD objects?** (Plain Old Delphi Objects, allowing UTF-8 Zero Allocation JSON from Dext).