Skip to main content
Aikeedo discovers routes by scanning classes for attributes. A plugin adds its own directory to that scan, then declares handlers the same way the core does.

Register your routes

Add the directory that contains your request handlers in boot():
src/Plugin.php
The mapper scans recursively, so pointing it at your src/ directory is usually enough. Point it at a subdirectory, such as __DIR__ . '/RequestHandlers', if you want to limit the scan.
Route discovery is cached when CACHE=true and DEBUG=false. After adding or changing a route on a cached installation, clear the cache from Status → Clear cache.

Anatomy of a handler

src/RequestHandlers/HelloRequestHandler.php
Every handler is a PSR-15 RequestHandlerInterface. The base class supplies the path prefix and the middleware stack; the #[Route] attribute supplies the rest of the path and the HTTP method.

Choose a base class

Prefixes and middleware are inherited, so #[Route(path: '/settings/hello')] on an admin view handler becomes GET /admin/settings/hello.
A handler that extends no base class gets no middleware at all: no body parsing, no user resolution and no error handling. Only do that when you need a minimal stack, such as for a webhook receiver, and add middleware explicitly. For ordinary public pages and endpoints, extend AbstractRequestHandler. See Public pages and endpoints.

Route attributes

Path syntax

Route parameters arrive as request attributes:
Give a route priority: Priority::HIGH when it would otherwise be shadowed by a more generic pattern.

Read the request

RequestBodyParserMiddleware decodes JSON and form bodies into a stdClass, so use property_exists() before reading optional fields.

Return a response

Shape your JSON with resources

Return a JsonSerializable resource rather than raw arrays, so your API matches the rest of Aikeedo:
src/Presentation/Resources/NoteResource.php
Presentation\Resources\ListResource wraps collections as {"object": "list", "data": [...]}, and CountResource wraps counts, which keeps your endpoints consistent with the core API.

Errors

Throw, and let ExceptionMiddleware translate the exception into a response:

Custom middleware

Middleware is a plain PSR-15 class, so you can autowire dependencies into it:
src/Middlewares/RequireFeatureMiddleware.php
Attach it with #[Middleware(RequireFeatureMiddleware::class)] on the handler or on a base class of your own.

Group routes with your own base class

src/RequestHandlers/NotesApi.php
Handlers that extend NotesApi are served under /api/notes, with the standard API middleware plus your feature check.