REST API skeleton · PSR-15 middleware

Dotkernel API

An open-source REST API skeleton for PHP, built on the Mezzio microframework and Laminas components over a Doctrine domain layer. OAuth 2.0, RBAC authorization, HAL payloads, standardized error responses and an OpenAPI 3.0 specification are assembled on install - not left as decisions for your first sprint.

PHP version for dotkernel/api Latest release of dotkernel/api License of dotkernel/api GitHub stars for dotkernel/api
Runtime Mezzio + Laminas
Persistence Doctrine ORM
License MIT
Request lifecycle All 19 stages →
CORSmezzio-cors
RouterFastRoute
AuthenticationOAuth 2.0
RBAC guardper route name
Your handlerPSR-15
ResponseHAL / problem+json
One resource, its links
What it is

A REST API you own from the first commit

Dotkernel API is the root of the Dotkernel Headless Platform: a REST API based on the Mezzio skeleton, using a PSR-compliant middleware stack as defined by the PHP Framework Interop Group. Rather than relying on elements built into a framework, business logic is built explicitly - from handlers to dependencies - so you keep full control over your business logic and data architecture.

It scales down to a single microservice and up to an enterprise-grade API, and it has been developed and released continuously since 2018.

Extending the power of

Doctrine ORM, not Active Record

Explicit wiring, no runtime magic

Auth, docs and errors on install

MIT licensed, actively maintained

What ships wired up

The parts every API needs, already connected

Each of these is configured and working in a fresh install. Nothing here is a placeholder you have to research and assemble before you can serve your first authenticated endpoint.

Security · Authentication

OAuth 2.0

Bearer tokens, issued and validated by the API itself.

Authentication runs on mezzio-authentication-oauth2, which wraps league/oauth2-server to provide OAuth 2.0 for PSR-7 / PSR-15 applications. Endpoints marked as authenticated require a valid Bearer token and answer 401 Unauthorized without one.

Security · Authorization

RBAC per route

Three levels of protection: none, authenticated, authorized.

Roles and their permissions are declared in configuration and allocated per route name, with role inheritance supported. An authenticated request that lacks the required permission gets a 403 Forbidden - decided by config, not scattered through your handlers.

Contract · Documentation

OpenAPI 3.0

A machine-readable contract, generated from the code that serves it.

Every module documents its endpoints in an OpenAPI.php file, which zircote/swagger-php turns into a specification rendered through Swagger UI or Redoc. A Postman collection and environment ship alongside it, so every endpoint is ready to call by hand.

Data · Persistence

Doctrine ORM

Your domain in entities, not in the query layer.

Doctrine ORM handles persistence, so you can focus on object-oriented business logic and treat storage as a secondary concern. Migrations, fixtures via dot-data-fixtures, and multiple database connections are part of the setup.

Contract · Responses

HAL & problem details

One predictable shape for resources, one for failures.

Payloads are built with mezzio-hal, describing each resource together with its relational links and embedded child resources. Errors return problem details responses via mezzio-problem-details, giving clients standardized error codes system-wide.

Contract · Negotiation

Content negotiation

Client and server agree on format and language up front.

Content negotiation is implemented out of the box through the Content-Type and Accept headers, so diverse systems can consume the same API without custom glue on either side. CORS preflight requests are recognized and configured by mezzio-cors.

Operations · Feedback

Error reporting endpoint

A channel for the bugs that never reach your logs.

Frontend developers can report incorrect behaviour by posting to /error-report with a token header. The API validates the request against configured tokens, domains and IPs before logging it - useful precisely when nothing fatal was thrown.

Operations · CLI

Commands & file locker

Scheduled work that refuses to trample itself.

Console commands are registered through dot-cli on top of Symfony Console, and php ./bin/cli.php route:list prints every endpoint the application exposes. The file locker, enabled by default, writes a lock file per command so a second instance cannot start while the previous run is still going - the safeguard cron jobs usually lack.

Operations · Mail

Transactional email

Account mail that works before you configure anything.

dot-mail wraps Symfony Mailer with templated messages, so account activation and password reset send out of a fresh install. It joins the request flow only where it is needed - the rest of the pipeline is unchanged whether a route sends mail or not.

Productivity · Scaffolding

dot-maker

New modules that already match the house style.

dot-maker generates project files and directories following the Dotkernel structure, and knows which files each application type needs. It replaces hand-copied boilerplate with consistent, standardized scaffolding.

Current release

What version 7 changed

The latest release moves identifiers to native database UUIDs and broadens platform support.

Native UUID v7

Identifier columns use the database's uuid type instead of binary, with values generated by ramsey/uuid. You keep full control of the UUID version without depending on database extensions.

PostgreSQL support

PostgreSQL joins the supported databases. Because native UUID is required, you need PostgreSQL or MariaDB 10.7 or later; MySQL is no longer supported, as it has no UUID data type.

PHP 8.5

The API targets PHP 8.5, with Dotkernel Admin on 8.4. Dependencies are kept current, and the ecosystem's own packages track the versions Laminas and Doctrine support.

Table prefixes

A configurable string can be prepended to every table name - the practical requirement when an API shares a database with an existing application.

Clearer database configuration

Multi-connection setups spell out which connection is the default and how to switch to another, based on scenarios from real projects.

Shared Core module

Common logic lives in a Core module kept as its own Git repository, which can be added as a submodule to any Dotkernel application so entities and queries stay consistent.

Change management

Evolution, not a wall of versions

Dotkernel API favours an evolution pattern with a sunsetting mechanism over maintaining parallel API versions. The same codebase evolves gradually and clients are given notice, instead of every change forking into another branch you have to keep alive.

The mechanism is DeprecationMiddleware: mark a handler with the #[ResourceDeprecation] attribute and the response carries sunset and link headers, so a client learns an endpoint is retiring from the endpoint itself rather than from a changelog it never read.

Full versioning stays reserved for major, format-level changes - the cases where it genuinely earns its maintenance cost. The two approaches are not mutually exclusive.

Coming from Laminas API Tools?

API Tools (formerly Apigility) is archived. Dotkernel API is an actively maintained alternative with a middleware architecture, a permissive MIT license and a Doctrine data layer.

The comparison below is drawn from the full side-by-side write-up on our blog.

Comparison

Dotkernel API vs Laminas API Tools

Feature API Tools (formerly Apigility) Dotkernel API
First release20122018
ArchitectureMVC, event drivenMiddleware
OSS lifecycleArchivedOSS lifecycle for dotkernel/api
PHP version≤ 8.2PHP version for dotkernel/api
StyleREST, RPCREST
Change managementVersioningDeprecations (API evolution)
DocumentationSwagger (automated)OpenAPI 3.0 (Swagger) and Postman (manual)
LicenseBSD-3MIT
Default DB layerlaminas-dbdoctrine-orm 3.x
AuthorizationACLRBAC guard
AuthenticationHTTP Basic / Digest, OAuth 2.0OAuth 2.0
Endpoint generatorYesdot-maker
PSR standardsPSR-7PSR-7, PSR-15

Comparison drawn against Dotkernel API v7. Read the reasoning behind each row in Dotkernel API versus Laminas API Tools.

The ecosystem

Runs alone, or as one of three

Dotkernel API is a complete application on its own. When you add Admin or Queue, all three declare the same Core namespaces, so a User means the same thing to the endpoint that creates it, the admin screen that moderates it, and the worker that emails it. The rest of the ecosystem is below.

Shared domain layer Core\App Core\Admin Core\User Core\Security Core\Setting

One set of entities and repositories, committed in each repository so a single-component start just works. Having many entities in Core does not oblige you to implement handlers for all of them - each application handles only what it needs.

Pair with · Back office

Admin

Manage the same data your API serves.

Table-based record management with RBAC guards, CSRF-protected forms and 2FA, over the same Core module. Start with either one and add the other later.

Pair with · Async work

Queue

Move slow work off the request cycle.

Background workers on Symfony Messenger - a TCP listener, Valkey streams, retries and a dead letter queue for what still fails.

Instead · Server-rendered

Frontend

When your users want pages, not payloads.

A web starter skeleton - user accounts, a contact form, sessions and RBAC-guarded controller actions, rendered on the server.

Smaller · Minimal

Light

A presentation site with no API behind it.

The smallest complete Mezzio application - routing, pipeline and Twig, six direct dependencies and no database layer.

Tooling · AI context

Dotboost

Teach your AI tools this architecture.

Drop-in Claude Code configuration - ten commands, seventeen skills and permission guardrails that keep your secrets out of the context window.

Every layer is also available on its own - see the packages lifecycle for the support status of each dot-* package.

Standards & quality

Built on interfaces, checked on every change

PSR-15 & PSR-7

Handlers implement RequestHandlerInterface and return ResponseInterface. The whole request path is middleware you can read top to bottom.

PSR-11 & PSR-4

The application is container-based, with dependencies declared in each module's ConfigProvider, and classes located by autoloader.

PSR-3 logging

Errors are logged through LoggerInterface via dot-errorhandler, centralizing how failures are recorded.

PHPStan at level 8

Static analysis runs at a strict rule level, in line with the choice made by projects like Doctrine and Composer.

Functional & unit tests

The skeleton ships with a test suite you extend rather than start, so new endpoints have somewhere to be tested from day one.

An active community

Updates arrive with bugfixes and improvements from the PHP community, and breaking changes come with companion articles and upgrade steps.

Get started

Install it and call an endpoint

Create the project with Composer, point it at PostgreSQL or MariaDB 10.7+, run the migrations, and you have an authenticated REST API with a browsable OpenAPI specification.

composer create-project dotkernel/api

The installer walks through database credentials and the initial configuration. Follow the installation guide for the exact command and post-install steps for your target version, then use dot-maker to scaffold your first module.

Questions along the way go to Dotkernel Discussions - the team answers issues on both Dotkernel and Laminas components.

Open source, in production

An API foundation you can read, audit and keep.

Dotkernel API is developed and led by the dev team at Apidemia - built first as an internal tool for handling complex architectures, released under MIT as our way of giving back to the community.