Building High-Performance APIs: A Guide to Using Maravel REST Wizard & Laravel CRUD Wizard Free in the Maravel Template
I wrote this tutorial with help from Gemini but, I manually fixed its hallucinations.
The Macropay-Solutions ecosystem provides a powerful suite of tools to automate REST API creation. If you are using the Maravel template (utilizing the ultra-fast v20.x kernel), you already have a massive head start: the template comes with laravel-crud-wizard-free built-in out of the box.
This technical guide covers how to leverage this built-in Laravel CRUD Wizard (Free) setup, and how to seamlessly upgrade to the Maravel REST Wizard (Paid). Because the official demo repositories are built for standard Laravel, we will also detail the specific architectural adjustments — such as Container hydration overrides — required to integrate custom Form Requests into Maravel’s sub-millisecond request lifecycle.
Prerequisite: File Scaffolding via the Generator
Before diving into the Wizard logic, it is highly recommended to leverage the macropay-solutions/laravel-crud-wizard-generator package.
Instead of writing boilerplate files by hand, this generator reads your database schema and automatically scaffolds the necessary models, requests, and controllers with exact column typing.
You can generate a fully decorated API resource with a single Artisan command:
php artisan make:api-resource operations --decorated
This command generates the base structure required for the wizards to function, allowing you to bypass the repetitive setup phase and focus purely on business logic, decorators, and routing.
Part 1: Leveraging the Built-In Free Version
Reference Repository: laravel-crud-wizard-decorator-free-demo
Because laravel-crud-wizard-free, laravel-crud-wizard-decorator-free and laravel-crud-wizard-generatorare included into the Maravel template composer.json file, your API already possesses powerful CRUFD (Create, Read, Update, Filter, Delete) capabilities from day one.
1. Setting Up the Core Files
- Update the Map: Update the \Support\DbCrudMap class that maps the resource name to its respective Controller.
- Maravel’s Prebuilt Routes: Because the wizard is native to the template, you do not need to write repetitive Route::get(), Route::post(), etc., for every single table. By iterating over your DbCrudMap, the Maravel template dynamically registers the undecorated and decorated CRUD routes for you (e.g., /api/{resource}). Look in /routes/web and just uncomment the defined routes.
2. The Maravel Form Request Override (CRITICAL)
Maravel strips away heavy global state initializers to maintain its boot speed.
To ensure the free wizard correctly validates incoming requests (especially during POST creation payloads) in Maravel, you have two choices:
Option A: Controller Method Override
You can explicitly define how the Form Request is built by overriding the validation method in your Base Controller or Wizard Trait. Apply this specific code block:
use Illuminate\Http\Request;
use App\Requests\ResourceRequest;
protected function validateCreateRequest(Request $request): void
{
// Deep clone the request and attach the resource label
$formRequest = ResourceRequest::createFrom($request, new ResourceRequest(resource: $this->label));
// Bind it to the Maravel app container
$formRequest->setContainer(\app());
// Trigger the validation lifecycle
$formRequest->validateResolved();
}
/**
* @throws \Throwable
*/
protected function validateUpdateRequest(Request $request): void
{
$this->validateCreateRequest($request);
}
This guarantees the ResourceRequest successfully navigates Maravel’s custom payload capture without throwing resolution errors.
Option B: Container Autowiring
Alternatively, FormRequest objects can be used directly in the controller method via Maravel's autowiring. However, for this to work natively without loading the heavy FormRequestServiceProvider, you need to intercept the Container resolution.
Uncomment and implement this code block inside your app/Application.php:
/**
* Uncomment to use \App\FormRequest
* @inheritdoc
* Used to avoid Illuminate\Support\ServiceProvider\FormRequestServiceProvider::boot
*/
protected function fireResolvingCallbacks($abstract, $object)
{
$this->fireCallbackArray($object, $this->globalResolvingCallbacks);
/** This avoids Illuminate\Support\ServiceProvider\FormRequestServiceProvider::boot */
if ($object instanceof \Illuminate\Http\FormRequest) {
\Illuminate\Http\FormRequest::createFrom($this['request'], $object);
$object->setContainer($this);
}
$this->fireCallbackArray(
$object,
$this->getResolvingCallbacksForType($abstract, $object)
);
/** This avoids Illuminate\Support\ServiceProvider\FormRequestServiceProvider::boot */
if ($object instanceof \Illuminate\Contracts\Validation\ValidatesWhenResolved) {
$object->validateResolved();
}
$this->fireAfterResolvingCallbacks($abstract, $object);
}
Part 2: Upgrading to the Maravel REST Wizard (Paid Version)
Reference Repository: laravel-crud-wizard-decorator-demo
While the Free version utilizes laravel-crud-wizard-free for standard Laravel compatibility, the Paid version utilizes the maravel-rest-wizard. This package takes the exact same metadata-driven architecture and hyper-optimizes it.
1. The Single ResourceRequest Architecture (For Both Free & Paid)
It is vital to understand that the “Single ResourceRequest” pattern is not locked inside the vendor library. The app/Requests/ResourceRequest.php file is coded and owned by the developer, meaning it can be used in both the Free and Paid versions.
Instead of generating 50 separate FormRequests for 50 tables, you manage all API validation through this single, intelligent class. If you examine the ResourceRequest.php file in the demo's production branch, you will see a sophisticated, closure-based validation map:
public function rules(): array
{
$result = ([
Client::RESOURCE_NAME => fn (): array => [
'name' => 'required|string|min:1|max:256',
'active' => 'in:0,1',
],
// Advanced multi-column uniqueness checks
OperationProductPivot::RESOURCE_NAME => fn (): array => [
'operation_id' => 'integer|exists:operations,id|unique:operation_product_pivots,operation_id,null,null,product_id,' . $this->get('product_id'),
],
][$this->resource ?? ''] ?? fn (): array => [])();
if ($this->getRealMethod() === 'POST') {
return $this->getValidatorsForCreate($result);
}
return $this->getValidatorsForUpdate($result);
}
Dynamic Partial Updates: The developer-owned ResourceRequest automatically formats rules for PATCH/PUT requests by stripping required constraints and applying sometimes. This eliminates the need to write separate validation logic for creation vs. updates.
2. Integrating into Maravel
To use this logic inside the Maravel template, the steps remain consistent whether you are using the Free or Paid wizard:
- Leverage the Generator: Scaffold your models, but instruct it (or manually refactor) to point all generated resources to your unified ResourceController.
- Apply the Validation Override: The object hydration constraint in Maravel remains the same. You must apply the identical validateCreateRequest/validateUpdateRequest override (or the Application.php container hack) shown in Part 1 to ensure the Form Request resolves correctly.
3. Performance Optimization Tip for Maravel REST Wizard
Because the ResourceRequest belongs to the developer, you can and should optimize its internal logic for Maravel v20.x. In the demo repository, the request relies on a foreach loop iterating over DbCrudMap::MODEL_FQN_TO_CONTROLLER_MAP to dynamically resolve resources and extract their ignore lists:
foreach (DbCrudMap::MODEL_FQN_TO_CONTROLLER_MAP as $modelFqn => $controllerFqn) {
if ($modelFqn::RESOURCE_NAME === $this->resource) {
return \resolve($modelFqn);
}
}
While this is fine for standard Laravel, if you are using the Paid Maravel REST Wizard to maximize throughput, an O(N) loop on every POST/PUT request is a bottleneck. Instead, utilize Maravel's ultra-fast static memory cache. You can compile your Crud Map into a flat PHP array during deployment and fetch it instantly:
// Turning an O(N) loop into an O(1) cache hit
\Illuminate\Container\Container::getCachedFileContentsFromMemory('crud_map.php')[$this->resource] ?? null;
By making this developer-side tweak to your ResourceRequest, you completely eliminate array iteration overhead, ensuring your API throughput remains strictly in the elite sub-millisecond benchmark tiers.
NOTE:
Detailed information about each project can be found here.

Top comments (0)