← API

API FEATURE

REST API

If you want clean REST, Semitexa already gives you a strong machine-facing contract without extra ceremony.

Feature Guide

A quick orientation block that answers the essential questions: what this feature does, how it works, why it matters, and the key concepts behind it.

What this does

Semitexa REST is explicit and typed. Payload DTOs own the route contract, version markers stay visible, and the response shape remains reviewable instead of drifting into improvised controller code.

How it works

A REST endpoint is declared on a payload with #[AsPayload], then marked as machine-facing with #[ExternalApi]. Optional concerns such as versioning, sparse fieldsets, expand parameters, and alternative representations stay attached to that same contract instead of being scattered through middleware and controllers.

Why it matters

REST should not mean accidental complexity. Semitexa keeps the HTTP surface boring in the best way: one clear route contract, one clear execution path, and machine-facing behavior that is explicit in code review.

Key concepts

#[AsPayload]
The typed request contract that owns the REST route.
#[ExternalApi]
Marks the payload as a public machine-facing REST endpoint.
#[ApiVersion]
Attaches explicit lifecycle metadata to a REST contract.

API

One dataset, multiple machine-facing shapes

These links hit the real `/demo/api/v1/products` endpoints. Change headers or query params and the response shape shifts without swapping handlers.

Collection /demo/api/v1/products?q=headphones
Detail /demo/api/v1/products/wireless-headphones?profile=full&expand=category,reviews
JSON-LD /demo/api/v1/products/wireless-headphones?format=ld
Consumer Headers / Params Outcome
Frontend Accept: application/json | X-Response-Profile: minimal Slim payload for interactive UI rendering.
Crawler Accept: application/ld+json Schema.org product document with semantic fields.
Dashboard Accept: application/json | expand=category,reviews | X-Response-Profile: full Expanded graph for internal admin views.
Search Accept: application/json | q=headphones Filtered collection with pagination metadata.
#[ExternalApi] #[ApiVersion] application/ld+json fields expand

Verified against Semitexa Ultimate 2026.09.19.1020

REST API

Semitexa REST endpoints use typed Payload DTOs as the contract boundary — no controller sprawl, no magic annotation wiring, and no separate serializer configuration step.

How it works

Mark a Payload with #[ExternalApi] to opt it into the machine-facing API surface. Add #[ApiVersion] to set version metadata and emit X-Api-Version on every response. The same handler can respond to JSON, JSON-LD, and sparse field requests by reading negotiation signals from the request without branching the route.

Why this matters

One endpoint can serve multiple API consumers without branching into separate handler trees. The contract is visible in the Payload DTO, the version is declared on the attribute, and the response shape is shaped from a typed presenter — not from ad-hoc json_encode calls scattered across the handler.

© Harold Abelson: "Programs must be written for people to read, and only incidentally for machines to execute."

List Payload Trusted input boundary
<?phpdeclare(strict_types=1);namespace App\Api\Product;use Semitexa\Api\Attribute\ApiVersion;use Semitexa\Api\Attribute\ExternalApi;use Semitexa\Core\Attribute\AsPublicPayload;#[AsPublicPayload(path: '/api/v1/products', methods: ['GET'], responseWith: ProductApiResponse::class)]#[ExternalApi(version: 'v1')]#[ApiVersion(version: '1.0.0')]final class ProductListPayload{    protected int $page = 1;    protected int $limit = 24;    public function getPage(): int { return $this->page; }    public function setPage(int|string|null $page): void { $this->page = max(1, (int) ($page ?? 1)); }    public function getLimit(): int { return $this->limit; }    public function setLimit(int|string|null $limit): void { $this->limit = min(100, max(1, (int) ($limit ?? 24))); }}

How it works

A REST endpoint is declared on a payload with #[AsPayload], then marked as machine-facing with #[ExternalApi]. Optional concerns such as versioning, sparse fieldsets, expand parameters, and alternative representations stay attached to that same contract instead of being scattered through middleware and controllers.

Why it matters

REST should not mean accidental complexity. Semitexa keeps the HTTP surface boring in the best way: one clear route contract, one clear execution path, and machine-facing behavior that is explicit in code review.

Key concepts

#[AsPayload]
The typed request contract that owns the REST route.
#[ExternalApi]
Marks the payload as a public machine-facing REST endpoint.
#[ApiVersion]
Attaches explicit lifecycle metadata to a REST contract.

Support Semitexa
Built for developers who prefer control over magic. Your support helps keep it fast, open, and evolving.

Donate via PayPal