apiato/core
APIato Core is the foundational package for APIato, an API-first Laravel framework built on the Porto architecture. It provides modular containers, authentication, authorization, routing, shared utilities, and code generation tools for scalable, maintainable backend applications.
apiato/core is the foundational package of the Apiato framework — a Laravel-based API starter kit built around the Porto architectural pattern (Containers → Sections → Actions/Tasks/Repositories/Transformers). You almost never install apiato/core in isolation; you get it transitively via:
composer create-project apiato/apiato my-api
After scaffolding:
app/Ship/ first. Ship is where cross-cutting concerns live (exception handler, global config, base migrations, OAuth/Passport setup). It explains how the framework wires itself.app/Containers/AppSection/User) end-to-end: Router → Controller → Request → Action → Task → Repository → Model → Transformer. That single container teaches you 90% of the framework.php artisan list apiato — because scaffolding is how you actually work day to day.Your first real use case is typically: add a new endpoint under an existing container (e.g. GET /v1/users/{id}), which means writing a Controller + Request + Transformer and re-using the existing Action.
Every feature lives inside a container (app/Containers/{Section}/{Container}). Create one with:
php artisan apiato:container
Then generate the pieces inside it:
php artisan apiato:action --container=AppSection@User
php artisan apiato:task --container=AppSection@User
php artisan apiato:request --container=AppSection@User
php artisan apiato:transformer --container=AppSection@User
The generator scaffolds the correct namespace, base class and boilerplate — do not hand-roll classes if a generator exists for it.
The canonical layering:
run() method, orchestrates Tasks, owns transaction boundaries.CreateUserTask, SendWelcomeEmailTask).?include= query parameters.class RegisterUserAction extends Action
{
public function __construct(
private CreateUserTask $createUserTask,
private SendWelcomeMailTask $sendWelcomeMailTask,
) {}
public function run(RegisterUserRequest $request): User
{
$user = $this->createUserTask->run($request->validated());
$this->sendWelcomeMailTask->run($user);
return $user;
}
}
Inject Tasks/Actions via the constructor — the container auto-resolves them because they are bound by the framework.
?include=Repositories extend Apiato\Core\Abstracts\Repositories\Repository and expose search(), find(), create(), update(), etc. They support the RequestCriteria out of the box, so a transformer with availableIncludes = ['roles', 'orders'] automatically honors GET /users/1?include=roles.
Extend the framework Request — do not use Laravel's default FormRequest. authorize() and rules() both live on the same class, and the controller signature (RegisterUserRequest $request, ...) auto-validates before the action runs.
Each container has UI/API/Routes/*.php. Register routes in the container's ServiceProvider via $this->router helpers ($this->routePublic(), $this->routePrivate(), $this->routeProtected(), $this->routeAdmin()). The middleware stack applied differs per helper, so use them rather than Route::middleware() by hand.
Tests live inside each container (Containers/AppSection/User/Tests). The framework testcase (ApiTestCase) includes helpers like $this->makeCall(), $this->getTestingUser(), and $this->assertResponseStatus() — always test at the endpoint level (functional), not just unit-test the Task.
Ship/Configs and generates classes at bootstrap. After changing config, run php artisan config:clear and (if the container registry seems stale) php artisan apiato:generate or its equivalent in your version. Many "my new container isn't discovered" bugs are cached bootstrap manifests.OZ9bGg). find($id) in repositories transparently decodes them — but if you call Model::find($id) directly, you'll get a miss. Always go through the repository for ID lookups.transform(), it will not appear. Adding a column to the DB is not enough — add it to the transformer and update its tests.Ship. Auth endpoints and Proxy helpers for password grants live under Ship/ and the Authentication container. Overriding token TTL, scopes or client config happens there, not in .env alone.Ship/Exceptions/Handler. Plain \Exception throws may produce non-standard responses.$this->routeProtected() vs $this->routePrivate() differ in auth guard; picking the wrong helper is a common source of "why is this public" bugs.SubAction for reuse, not inheritance. It's tempting to build deep action hierarchies; instead compose small SubActions — this keeps each Task/Action independently testable, which is the whole point of the layering.Ship; keep feature code in its App container. Mixing the two erodes the architecture quickly.How can I help you explore Laravel packages today?