Skip to content
Back to skills

Dmvcframework Minimal Api

ASecurity

Use when building a DelphiMVCFramework service with lambda/anonymous-method routes instead of controller classes — Minimal API. Triggers on "minimal API", "MapGet", "MapPost", "MapMethods", "route group", "endpoint filter", "HTTP filter", "TMVCRouteGroup", "AsWeb", "lambda routes", "no controller", "Prefix", "UseHTTPFilter", "TMVCFormFile", "MVCFromQueryString", "wizard Minimal API preset". Covers both Minimal REST APIs and Minimal web apps (TemplatePro/HTMX via .AsWeb).

  • 20 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 4, 2026
developmentrustgosqlreactexpressgitapidatabasebackendsecurity

Works with

  • cli
  • api

Security analysis

A100/100

Scanned October 5, 2026

npx -y skills add danieleteti/delphi-ai-skills --skill dmvcframework-minimal-api --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Dmvcframework Minimal Api?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Dmvcframework Minimal Api
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/danieleteti-dmvcframework-minimal-api/badge)](https://www.skillsdirectory.com/skills/danieleteti-dmvcframework-minimal-api)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: dmvcframework-minimal-api
description: Use when building a DelphiMVCFramework service with lambda/anonymous-method routes instead of controller classes — Minimal API. Triggers on "minimal API", "MapGet", "MapPost", "MapMethods", "route group", "endpoint filter", "HTTP filter", "TMVCRouteGroup", "AsWeb", "lambda routes", "no controller", "Prefix", "UseHTTPFilter", "TMVCFormFile", "MVCFromQueryString", "wizard Minimal API preset". Covers both Minimal REST APIs and Minimal web apps (TemplatePro/HTMX via .AsWeb).
---

# DMVCFramework — Minimal API

Routes are anonymous methods registered on a **route group**, not methods of a controller class.
Same engine, same serializer, same ActiveRecord as the controller-based API — only the routing layer differs.

Everything below is copied from `sources/MVCFramework.MinimalAPI.pas`, `sources/MVCFramework.Filters.pas`
and the samples. **Do not invent names** — the DSL does not follow ASP.NET spelling (there is no `MapGroup`,
no `app.Use`, no `OkResponse`).

## When in doubt about an API — verify it, never guess

Never invent an identifier or answer from memory. If you need a signature this skill does not cover, ask the
user for the path to their **DelphiMVCFramework checkout** and read `sources/` (and the matching `samples/`
project); failing that, read the official repository —
[sources](https://github.com/danieleteti/delphimvcframework/tree/master/sources) ·
[samples](https://github.com/danieleteti/delphimvcframework/tree/master/samples).
If you still cannot verify it, **say so**. Where a skill and a sample disagree, **the sample wins**.

---

## Delphi Language Target

Delphi 11 Alexandria or later — inline `var` declarations and `for var` loops are fine, and this skill's
examples use them. Do not use Delphi 13 Florence-only syntax (`NameOf`, inline `if` expressions).
For the language and the RTL themselves — version gating, lifetime, strings, generics, threading — load the
**`delphi`** skill.

## When to use

- New service where a controller class per resource adds no value
- Route-level filters/composition (auth per group, versioned prefixes)
- Web app with lambda handlers rendering TemplatePro views (`.AsWeb`)

Use the controller-based API (skill `dmvcframework`) when you want class-level inheritance, `OnBeforeAction`
hooks, or the classic middleware chain as the primary mechanism.

---

**REQUIRED REFERENCE — `dmvcframework-security`.** Any endpoint that accepts input from a client (body,
query string, header, cookie, upload, URL) must follow it: access control and IDOR, mass assignment,
SQL injection, XSS, CSRF, path traversal, uploads, security headers, JWT, secrets. Invoke it whenever you
write or review such an endpoint — not only when the user says "security".

---

## 0. STOP — start from a wizard project

**Never create the project from scratch. Never hand-write the `.dpr` bootstrap.**

The IDE wizard ships two Minimal API presets — **Minimal API RESTful** and **Minimal API WebApp** — and both
generate a correct, compiling project with the routing already wired. Your job is to add routes to it.

**Step 1 — detect it.** The user is expected to have run the wizard and started the agent **from inside the
project folder**. A Minimal API wizard project has:

```
*.dpr              Boot + RegisterServices + RunServer  (Indy Direct by default; a WebModule here means WebBroker/ISAPI/Apache — also fine)
BootConfigU.pas    dotEnv + LoggerPro
EngineConfigU.pas  ConfigureEngine — view engine, exception handler, HTTP filters
RoutesU.pas        ConfigureRoutes — YOUR ROUTES GO HERE
ServicesU.pas      DI registrations
EntitiesU.pas      entities
bin/.env           port and settings
```

Read `RoutesU.pas` and `EngineConfigU.pas` before writing anything, and follow their conventions.

**Step 2 — if there is no wizard project, stop.** Do not scaffold one. Tell the user:

> This skill works on a project generated by the DMVCFramework IDE wizard, and I do not see one here.
> Please create it first:
>
> **Delphi IDE → File → New → Other → Delphi Projects → DelphiMVCFramework → New DMVCFramework Application**
>
> Pick **Minimal API RESTful** (or **Minimal API WebApp** for HTML pages). Accept the defaults — the server
> backend is **Indy Direct**. Compile and run it once. Then `cd` into the project folder, start me there, and
> tell me which routes to add.

Then wait.

**The host may be WebBroker (ISAPI, Apache) — that is fine.** Keep it, do not migrate it, do not suggest
migrating it. Everything above the host is identical on every backend. See `dmvcframework`,
`reference/servers.md`.

The section below documents the bootstrap the wizard generates, so you can **read** it — not so you can
retype it.

---

## 1. Bootstrap — what the wizard generated

```delphi
// Project.dpr — already written by the wizard. Do not recreate it.
begin
  IsMultiThread := True;
  MVCSerializeNulls := True;
  Boot;                                          // BootConfigU: dotEnv + LoggerPro
  RegisterServices(DefaultMVCServiceContainer);  // ServicesU
  DefaultMVCServiceContainer.Build;              // mandatory
  RunServer(dotEnv.Env('dmvc.server.port', 8080));
end.

procedure RunServer(APort: Integer);
var
  lEngine: TMVCEngine;
  lServer: IMVCServer;
begin
  lEngine := TMVCEngine.Create(
    procedure(Config: TMVCConfig)
    begin
      Config[TMVCConfigKey.DefaultContentType] := TMVCMediaType.APPLICATION_JSON;
    end);
  try
    ConfigureEngine(lEngine);        // EngineConfigU: view engine, exception handler, HTTP filters
    ConfigureRoutes(lEngine.Root);   // RoutesU: takes a TMVCRouteGroup<TObject>, NOT the engine
    lServer := TMVCServerFactory.CreateIndyDirect(lEngine);
    lServer.RunAndWait(APort);
  finally
    lEngine.Free;
  end;
end;
```

`ConfigureRoutes` signature used by the wizard/showcase projects:

```delphi
procedure ConfigureRoutes(const ARoot: TMVCRouteGroup<TObject>);
```

**Ordering rule:** add classic middlewares **before** the first `MapXxx` call. The minimal-API dispatcher is
installed lazily on the first `Map` and short-circuits matching routes — middlewares added after it never run
for minimal routes.

---

## 2. Route registration DSL

Everything hangs off a **group**. There are no `Map*` methods on `TMVCEngine`.

```delphi
// TMVCEngine helpers
function Root: TMVCRouteGroup<TObject>;                      // = Prefix('')
function Prefix(const APrefix: string): TMVCRouteGroup<TObject>; overload;
function Prefix<T: class>(const APrefix: string; const AData: T;
                          AOwns: Boolean = True): TMVCRouteGroup<T>; overload;
function UseHTTPFilter(const AFilter: TMVCHTTPFilter): TMVCEngine;
```

`TMVCRouteGroup<T>` — **a record with value semantics**:

```delphi
function Prefix(const APath: string): TMVCRouteGroup<T>;             // nested; inherits filters + rkWeb
function Use(const AFilter: TMVCEndpointFilter): TMVCRouteGroup<T>;
function AsWeb: TMVCRouteGroup<T>;                                    // web route: hidden from OpenAPI
function AsApi: TMVCRouteGroup<T>;                                    // default
function MapGet   (const APath: string; const AHandler: TMVCMinimalFunc): TMVCRouteHandle;
function MapPost  (...) : TMVCRouteHandle;
function MapPut   (...) : TMVCRouteHandle;
function MapPatch (...) : TMVCRouteHandle;
function MapDelete(...) : TMVCRouteHandle;
function MapMethods(const AVerbs: array of TMVCHTTPMethodType; const APath: string;
                    const AHandler: TMVCMinimalFunc): TMVCRouteHandle;
```

Each `Map*` (and `MapMethods`) has generic overloads for **1 to 4** typed handler arguments:
`MapGet<T1>`, `MapGet<T1,T2>`, `MapGet<T1,T2,T3>`, `MapGet<T1,T2,T3,T4>`.
**Always write the type arguments** — `lWeb.MapGet<TWebContext>('/', function(Ctx: TWebContext): IMVCResponse ...)`.
Delphi does not infer them from the anonymous method: without them the call fails with *E2250 There is no
overloaded version of 'MapGet'*. The plain `MapGet(APath, AHandler)` takes only a handler with **no** arguments.

> **Value-semantics trap:** `Use`/`Prefix`/`AsWeb` return a **new** group.
> `lGroup.Use(Authorize);` on its own line is a **no-op**. Chain it or reassign:
> `lGroup := lGroup.Use(Authorize);`

Path syntax = standard DMVC: `($id)`, with optional constraint `($id:int)`.
Constraints: `int`, `int64`, `float`, `bool`, `guid`, `date`, `sqids`. A failed constraint means the route
simply does not match (→ 404 or the next route). An unknown constraint name raises `EMVCException` when the
route is registered, at startup.
Trailing wildcard: `($slug:*)` captures the rest of the path, slashes included, as a `string`.

### Route metadata — `TMVCRouteHandle` (returned by every `Map*`)

```delphi
lRoutes.MapGet('/customers', ...)
  .WithName('customers.list')        // unique engine-wide; duplicate/empty raises EMVCMinimalAPI
  .WithSummary('List customers')
  .WithDescription('...')
  .WithTags(['customers'])
  .WithDeprecated
  .Produces<TCustomer>
  .WithOpenAPI(False)                // hide from the spec
  .Use(RequireRole('admin'));        // route-scoped filter, runs after the group's
```

---

## 3. Handler signatures

The **only** accepted shapes — all return `IMVCResponse`, max 4 args, no `procedure`:

```delphi
TMVCMinimalFunc              = reference to function: IMVCResponse;
TMVCMinimalFunc<T1>          = reference to function(Arg1: T1): IMVCResponse;
TMVCMinimalFunc<T1,T2>       = reference to function(Arg1: T1; Arg2: T2): IMVCResponse;
TMVCMinimalFunc<T1,T2,T3>    = reference to function(Arg1: T1; Arg2: T2; Arg3: T3): IMVCResponse;
TMVCMinimalFunc<T1,T2,T3,T4> = reference to function(Arg1: T1; Arg2: T2; Arg3: T3; Arg4: T4): IMVCResponse;
```

---

## 4. Parameter binding — driven by the argument TYPE

Resolution order (`TMVCMinimalArgResolver.Resolve<T>`):

| Arg type | Bound from |
|----------|-----------|
| `TWebContext` | the request context |
| `TMVCFormFile` | the **first** uploaded multipart file (`nil` if none) |
| **interface** | DI — `ServiceContainerResolver`. Unresolvable → 500 |
| **record** | hybrid binding, per-field (see below) |
| **class** | group data if the type matches; else POST/PUT/PATCH → JSON body; else GET/DELETE → writable properties filled from the query string |
| primitive (`Integer`, `Int64`, `string`, `Boolean`, `Double`, `TGUID`, `TDateTime`…) | the **next unconsumed route segment**, in declaration order |

Two rules that surprise everyone:

1. **Only interfaces get DI.** A concrete class argument is *never* a service — it is body/query/group data.
2. **A primitive argument binds to a route segment, not to a query param.** `?page=2` will **not** land in a
   bare `Integer` arg. Use a record with `[MVCFromQueryString]`.

Objects bound as arguments are owned by the framework and freed after the handler. Never free them.

### Records — field-level binding

```delphi
type
  TCustomerSearch = record
    [MVCFromQueryString('q', '')]      Query: string;
    [MVCFromQueryString('page', 1)]    Page: Integer;
    [MVCFromQueryString('tag')]        Tags: TArray<string>;   // repeated ?tag=a&tag=b
    [MVCFromHeader('X-Tenant')]        Tenant: string;
    [MVCFromCookie('sid', '')]         SessionId: string;
    City: string;                      // no attribute → route segment, then query string, by field name
  end;

  TCreateCustomer = record
    [MVCFromBody]                      Customer: TCustomer;    // class field ← JSON body
  end;
```

- `[MVCFromContentField('name')]` — form-urlencoded / multipart field. `TArray<string>` gives multi-value;
  any other `TArray<System.*>` **raises**.
- `[MVCFromFile('field')]` only renames the form field for a `TMVCFormFile` / `TArray<TMVCFormFile>` field —
  the binding itself is by type.

`TMVCFormFile`: `FieldName`, `FileName`, `ContentType`, `Size: Int64`, `ContentStream: TStream`
(request-owned — **do not free**), `ContentAsBytes`, `ContentAsString(AEncoding)`, `SaveToFile(APath)`.

---

## 5. Return values — standalone response builders

Handlers must return `IMVCResponse`. The builders are **standalone functions** (not controller methods, and
**not** named `OkResponse`/`NotFoundResponse` — that is the controller-side naming):

```delphi
Ok;  Ok(Body: TObject; Owns: Boolean = True);  Ok(Message: string);
Created(Location, Message);  Created(Location, Body, Owns);
NoContent;  Accepted;  NotModified;
NotFound / BadRequest / Unauthorized / Forbidden / Conflict /
  UnsupportedMediaType / UnprocessableEntity / InternalServerError   // each ×3 overloads
Redirect(Location);  Redirect(Location, Permanent, PreserveMethod = False);
Status(Code);  Status(Code, Message);  Status(Code, Body, Owns);
ProblemDetails(StatusCode, Title, Detail = '', Instance = '');
```

- `Ok(TObject)` serializes and **frees** the object (`Owns = True`) — works for `TObjectList<T>`,
  entities, `TJsonObject`.
- `Ok(string)` wraps the string as `{"message": "..."}`.
- `ProblemDetails(...)` is the RFC 7807 object itself, sent as `application/problem+json` (on 3.5.0-rc7 and
  earlier it came out wrapped in `{"data": ...}` as `application/json`).
- **Records cannot be returned.** There is no `Ok(record)` overload — build a class or a `TJsonObject`.
- The result is mutable: `Result := Ok(lData); Result.StatusCode := 201;`
- HTML: `RenderView` (§7) for a template; `Html(const AHtml: string)` for a small fragment with no template
  (an HTMX swap target) — it sends the string **as is**, nothing escaped, so encode any untrusted value in it.

---

## 6. Filters — two kinds, do not mix them up

```delphi
TMVCEndpointFilterNext = reference to function: IMVCResponse;
TMVCEndpointFilter     = reference to function(const AContext: TWebContext;
                           const ANext: TMVCEndpointFilterNext): IMVCResponse;

TMVCHTTPFilterNext     = reference to procedure;
TMVCHTTPFilter         = reference to procedure(const AContext: TWebContext;
                           const ANext: TMVCHTTPFilterNext);
```

| | EndpointFilter | HTTPFilter |
|--|----------------|-----------|
| Attached to | a group (`group.Use`) or one route (`handle.Use`) | the engine (`lEngine.UseHTTPFilter`) |
| Fires | only when a route matches | on **every** request, wrapping routing itself |
| Works with | `IMVCResponse` in/out | mutates `Ctx.Response` directly |
| Order | after all HTTPFilters; first `Use`d = outermost | all HTTPFilters run before any EndpointFilter |

Skipping `ANext()` short-circuits the chain. Nested `Prefix` inherits the parent's filters.

**Custom endpoint filter — the whole shape:**

```delphi
function RequireLogin(const ARedirectTo: string): TMVCEndpointFilter;
begin
  Result :=
    function(const Ctx: TWebContext; const Next: TMVCEndpointFilterNext): IMVCResponse
    begin
      if Ctx.Session['user'].IsEmpty then
        Result := Redirect(ARedirectTo)
      else
        Result := Next();
    end;
end;
```

### Ready-made filters (`MVCFramework.Filters`)

**EndpointFilters** — `MemorySession(TimeoutMinutes = 0; HttpOnly = True; Secure = False)` · `FileSession(...)` ·
`DatabaseSession(...)` · `CORS(...)` · `JWT(AuthHandler, ClaimsSetup, Secret, LoginURLSegment, ClaimsToCheck,
LeewaySeconds, HMACAlgorithm)` · `BasicAuth(Validator, Realm)` · `Authorize` ·
`RequireRole(Role)` / `RequireRole(Roles: TArray<string>)` (any-of) · `ActiveRecord(ConnectionDefName)`

**HTTPFilters** — `StaticFiles(Prefix, RootFolder, DefaultDocument = 'index.html')` ·
`Compression(Threshold = 1024)` · `ETag` · `IPBlock(...)` · `RateLimit(Max = 60, WindowSeconds = 60)` ·
`RequestLog` · `CORSFilter(...)` · `SecurityHeaders` · `Shutdown(...)` · `Analytics(...)` · `Trace(...)` ·
`Redirect(...)` · `RangeMedia(URLPath, DocumentRoot)` · `OpenAPI(Engine, Info, '/openapi.json')` · `Swagger(...)`
(`RateLimitRedis` lives in `MVCFramework.Filters.Redis`.)

---

## 7. Web mode — TemplatePro + HTMX

```delphi
// EngineConfigU
AEngine.SetViewEngine(TMVCTemplateProViewEngine);
AEngine.UseExceptionHandler('error', 'MyApp');
// config keys: ViewPath, DefaultViewFileExtension, ViewCache
```

Mark the group `.AsWeb` (excludes it from OpenAPI) and add a session filter:

```delphi
var lWeb := ARoot.AsWeb.Use(MemorySession(30, True, dotEnv.Env('SESSION_COOKIE_SECURE', True)));  // as the wizard

lWeb.MapGet<TWebContext>('/customers',
  function(Ctx: TWebContext): IMVCResponse
  var
    lCustomers: TObjectList<TCustomer>;
  begin
    lCustomers := GetCustomers;
    try
      ViewData['customers'] := lCustomers;
      // HTMX asks for the table only; a normal request gets the whole page
      if Ctx.Request.IsHTMX and not Ctx.Request.HXIsBoosted
         and not Ctx.Request.HXIsHistoryRestoreRequest then   // uses MVCFramework.HTMX
        Result := RenderView('customers/table')
      else
        Result := RenderView('customers/index');
    finally
      lCustomers.Free;               // ViewData owns nothing
    end;
  end);
```

Ambient web globals (valid **only** inside a minimal-API request, otherwise `EMVCMinimalAPI`):

```delphi
function ViewData: TMVCViewDataObject;
function RenderView(const AViewName: string): IMVCResponse;
function RenderView(const AViewName: string; const AOnBeforeRender: TMVCSSVBeforeRenderCallback): IMVCResponse;
function RenderViews(const AViewNames: TArray<string>; const AUseCommonHeadersAndFooters: Boolean = True): IMVCResponse;
```

`ViewData` is the **only** ambient helper by design — session, request, HTMX state must come in as a typed
`TWebContext` argument. There is **no** `TMVCEngine.WebRoot` / `WebPrefix` (some old sample comments say
otherwise; they are stale).

Session: read/write `Ctx.Session['user']`, end with `Ctx.SessionStop`.
Page vs fragment: the handler above; the template pair, TemplatePro and HTMX are in `dmvcframework-webapp`.

**Content negotiation:** if an `rkApi` and an `rkWeb` route share verb+path, the winner is scored on
`Accept`/`Content-Type` (web wins on `text/html`, api on `application/json`). Ties → first registered.

---

## 8. Validation

- **Bound classes:** validated automatically if the class carries ≥1 validator attribute or descends from
  `TMVCValidatable` — after deserialization, before the handler runs.
- **Bound records:** validated **unconditionally** (`ValidateRecord`); fields with validator attributes are checked.
  Error keys are field names; no `OnValidate`, no nesting, and cross-field validators (`MVCCompareField`, …)
  get no owner object and do not check — use a class for rules that span two fields.
- Failure raises `EMVCValidationException` → rendered as RFC-7807 ProblemDetails with **422**
  (binding errors → **400**: `EMVCMinimalAPI` for a route/query value, `EMVCException` for malformed JSON). The body has `"detail": "Validation failed for fields:
  Email, FirstName"` plus an `"errors"` object with the per-field messages (`{"Email": "...", ...}`).
  `errors` arrived after 3.5.0-rc7: on rc7 and earlier only `detail` is there.
- Validators read **properties** of a class (fields of a record); on a `NullableXxx` property only
  `MVCRequired` checks anything.
- HTML form posts (`Ctx.Request.ContentFields`) are not validated for you: copy the fields into an object,
  validate, re-render with `formModel`/`formErrors` and 422.

The full attribute list, the error-map response, the form re-render pattern and custom validators are in the
`dmvcframework` skill, `reference/validation.md`.

```delphi
type
  TCreateCustomerReq = record
    [MVCRequired] [MVCMinLength(2)]  FirstName: string;
    [MVCRequired]                    LastName: string;
    [MVCEmail]                       Email: string;
  end;
```

---

## 9. Worked example

```delphi
procedure ConfigureRoutes(const ARoot: TMVCRouteGroup<TObject>);
begin
  var lApi := ARoot.Prefix('/api');

  lApi.MapGet<TCustomerSearch, ICustomerService>('/customers',
    function(Search: TCustomerSearch; Svc: ICustomerService): IMVCResponse   // record + DI interface
    begin
      Result := Ok(Svc.Search(Search.Query, Search.Page));                   // TObjectList → owned & freed
    end).WithName('customers.list').Produces<TCustomer>;

  lApi.MapGet<Integer, ICustomerService>('/customers/($id:int)',
    function(ID: Integer; Svc: ICustomerService): IMVCResponse               // primitive ← route segment
    var
      lCustomer: TCustomer;
    begin
      lCustomer := Svc.GetByID(ID);
      if lCustomer = nil then
        Exit(NotFound('Customer not found'));
      Result := Ok(lCustomer);
    end);

  lApi.MapPost<TCreateCustomerReq, ICustomerService>('/customers',
    function(Req: TCreateCustomerReq; Svc: ICustomerService): IMVCResponse   // record → validated
    var
      lID: Integer;
    begin
      lID := Svc.Create(Req.FirstName, Req.LastName, Req.Email);
      Result := Created('/api/customers/' + lID.ToString, 'Customer created');
    end);

  // admin group — filters applied to every route below
  var lAdmin := lApi.Prefix('/admin').Use(Authorize).Use(RequireRole('admin'));

  lAdmin.MapDelete<Integer, ICustomerService>('/customers/($id:int)',
    function(ID: Integer; Svc: ICustomerService): IMVCResponse
    begin
      Svc.Delete(ID);
      Result := NoContent;
    end);
end;
```

---

## 10. Common mistakes

| Mistake | Reality |
|---------|---------|
| `lEngine.MapGet(...)` | No `Map*` on the engine. Go through `lEngine.Root` / `Prefix(...)` |
| `MapGroup('/admin')` | Does not exist. It is `Prefix('/admin')` |
| `Result := OkResponse(x)` | Controller-side name. Minimal API uses standalone `Ok(x)` |
| `lGroup.Use(F);` on its own line | Groups are records — the result is discarded. Chain or reassign |
| `function(Page: Integer)` for `?page=2` | Primitives bind to **route segments**. Use a record + `[MVCFromQueryString]` |
| `function(Svc: TCustomerService)` | Only **interfaces** get DI. A class arg means body/query/group data |
| Returning a record | No `Ok(record)` overload. Return a class or `TJsonObject` |
| Freeing a bound arg / `TMVCFormFile.ContentStream` | Framework-owned. Do not free |
| Adding a middleware after the first `MapXxx` | It will not run for minimal routes. Register middlewares first |
| `procedure` handler | Handlers are always `function ... : IMVCResponse` |

---

## 11. Key units

| Unit | Purpose |
|------|---------|
| `MVCFramework.MinimalAPI` | `Root`/`Prefix`, `TMVCRouteGroup<T>`, `TMVCRouteHandle`, `TMVCMinimalFunc`, `TMVCFormFile`, `ViewData`, `RenderView` |
| `MVCFramework.Filters` | All ready-made endpoint/HTTP filters |
| `MVCFramework.Filters.Redis` | `RateLimitRedis` |
| `MVCFramework` | `TMVCEngine`, `IMVCResponse`, response builders, `[MVCFromBody/QueryString/Header/Cookie/ContentField/File]` |
| `MVCFramework.Server.Factory` | `TMVCServerFactory.CreateIndyDirect / CreateHttpSys / CreateWebBroker` |
| `MVCFramework.HTMX` | `Request.IsHTMX`, `Response.HXSet*` helpers |
| `MVCFramework.Container` | `DefaultMVCServiceContainer`, `RegisterType`, `Build` |

## 12. Reference samples

| Folder | Shows |
|--------|-------|
| `samples/minimal_api/` | REST routes, groups, typed `Prefix<T>` group data, OpenAPI |
| `samples/minimal_api_webapp/` | `.AsWeb`, `MemorySession`, `RequireLogin`, RenderView |
| `samples/wizard_showcase/rest/` | Wizard project shape: dpr → BootConfig → EngineConfig → Routes |
| `samples/wizard_showcase/web/` | Same, web flavour + TemplatePro helpers + HTMX templates |

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.