<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Loic Aron Mbassi Ewolo</title>
    <description>The latest articles on DEV Community by Loic Aron Mbassi Ewolo (@nameless0l).</description>
    <link>https://dev.to/nameless0l</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4035374%2F6a718bf4-7c77-47b0-b229-3631f1fc55eb.jpg</url>
      <title>DEV Community: Loic Aron Mbassi Ewolo</title>
      <link>https://dev.to/nameless0l</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nameless0l"/>
    <language>en</language>
    <item>
      <title>Your Mermaid diagram is a valid input for a Laravel API generator</title>
      <dc:creator>Loic Aron Mbassi Ewolo</dc:creator>
      <pubDate>Sat, 25 Jul 2026 14:45:40 +0000</pubDate>
      <link>https://dev.to/nameless0l/your-mermaid-diagram-is-a-valid-input-for-a-laravel-api-generator-11o7</link>
      <guid>https://dev.to/nameless0l/your-mermaid-diagram-is-a-valid-input-for-a-laravel-api-generator-11o7</guid>
      <description>&lt;p&gt;Data models get designed in diagrams and implemented in code, and the two drift apart from day one. The diagram in your README says &lt;code&gt;Post belongsTo Category&lt;/code&gt;; the code says otherwise; nobody notices until a migration fails.&lt;/p&gt;

&lt;p&gt;The fix I landed on for &lt;a href="https://github.com/Nameless0l/laravel-api-generator" rel="noopener noreferrer"&gt;laravel-api-generator&lt;/a&gt;: make the diagram the input. Two formats work, YAML and Mermaid.&lt;/p&gt;

&lt;h2&gt;
  
  
  YAML
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# api-schema.yaml&lt;/span&gt;
&lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;postman&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;entities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Category&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string unique&lt;/span&gt;
    &lt;span class="na"&gt;relations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;posts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hasMany Post&lt;/span&gt;

  &lt;span class="na"&gt;Post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;text&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;enum(draft,published) default=draft&lt;/span&gt;
      &lt;span class="na"&gt;published_at&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;datetime nullable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan make:fullapi &lt;span class="nt"&gt;--schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;api-schema.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at what's missing: &lt;code&gt;Post&lt;/code&gt; never declares &lt;code&gt;belongsTo Category&lt;/code&gt;, and there's no &lt;code&gt;category_id&lt;/code&gt; field anywhere. The generator synthesizes the inverse relation and its foreign key column. You declare one side, like you would explain it to a colleague, and both sides exist in the code.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;enum&lt;/code&gt; line generates the backed enum class, the model cast, &lt;code&gt;Rule::enum&lt;/code&gt; validation and a factory that picks random cases. I wrote about that chain in more detail in &lt;a href="https://dev.to/nameless0l/a-complete-laravel-api-with-clean-architecture-in-30-seconds-tests-included-1h0h"&gt;part 1&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is the one I use most, because GitHub renders it in the PR:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffqd8zhh5e3wqlzplfe4h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffqd8zhh5e3wqlzplfe4h.png" alt="mermaid diagram " width="798" height="1701"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mermaid
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan make:fullapi &lt;span class="nt"&gt;--mermaid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;docs/erd.mmd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both &lt;code&gt;erDiagram&lt;/code&gt; and &lt;code&gt;classDiagram&lt;/code&gt; work. Cardinalities map to the right Eloquent relations, &lt;code&gt;UK&lt;/code&gt; markers become unique fields, a &lt;code&gt;deleted_at&lt;/code&gt; column enables soft deletes. Markdown fences and comments are stripped, so a diagram pasted straight from an AI chat works as-is. Review the diagram in the pull request, merge, generate. No drift, because there's nothing to drift from.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://marketplace.visualstudio.com/items?itemName=Nameless0l.laravel-api-generator" rel="noopener noreferrer"&gt;VS Code extension&lt;/a&gt; takes the same Mermaid input without the terminal, and it draws the reverse view too: an interactive diagram of your entities (zoom, pan) inside the editor. The diagram goes in, the API comes out, and the canvas shows you what actually exists.&lt;/p&gt;

&lt;p&gt;[VISUEL 15 (fichier 13) : vraie capture du diagramme interactif de l'extension, habillée]&lt;/p&gt;

&lt;p&gt;[VISUEL 10 (fichier 13) : split-screen diagramme Mermaid rendu / arborescence générée]&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom primary keys propagate
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Country&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string primary&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;relations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;cities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hasMany City&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was the request that took me the longest in v3.6. &lt;code&gt;City&lt;/code&gt; gets a &lt;code&gt;country_code&lt;/code&gt; column typed like the key, &lt;code&gt;-&amp;gt;references('code')&lt;/code&gt; in the migration, &lt;code&gt;exists:countries,code&lt;/code&gt; in validation, and the model declares &lt;code&gt;$primaryKey&lt;/code&gt;, &lt;code&gt;$incrementing&lt;/code&gt; and &lt;code&gt;$keyType&lt;/code&gt;. The generated tests use &lt;code&gt;getKey()&lt;/code&gt; so the same suite passes with either key style. Polymorphic relations (&lt;code&gt;morphTo&lt;/code&gt;, &lt;code&gt;morphOne&lt;/code&gt;, &lt;code&gt;morphMany&lt;/code&gt;) are supported in schemas too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Day 30
&lt;/h2&gt;

&lt;p&gt;Every scaffolder demos well on day 1 and gets deleted on day 30, because regenerating would wipe your manual work. So regeneration isn't the evolution path here. Patching is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan make:fullapi Post &lt;span class="nt"&gt;--add-fields&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"excerpt:text,seo_title:string"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This writes an incremental &lt;code&gt;Schema::table&lt;/code&gt; migration with a &lt;code&gt;down()&lt;/code&gt;, and patches &lt;code&gt;$fillable&lt;/code&gt;, the casts, the PHPDoc, the validation rules, the factory and the resource in place. Your custom methods are not touched. Fields that already exist are skipped. The DTO and the tests are deliberately left alone and reported as manual follow-ups, because guessing there felt more dangerous than useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical notes
&lt;/h2&gt;

&lt;p&gt;Dev dependency, MIT, generated code has no reference to the package. Works in CI and with AI coding agents; one YAML file describing the whole API turns out to be a much better target for an agent than "create twelve files". The extension mentioned above also adds a form builder with live preview, imports from a database or an OpenAPI spec, and one-click migrate, seed and docs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docs: &lt;a href="https://nameless0l.github.io/laravel-api-generator/" rel="noopener noreferrer"&gt;https://nameless0l.github.io/laravel-api-generator/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/Nameless0l/laravel-api-generator" rel="noopener noreferrer"&gt;https://github.com/Nameless0l/laravel-api-generator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Part 1 (architecture): &lt;a href="https://dev.to/nameless0l/a-complete-laravel-api-with-clean-architecture-in-30-seconds-tests-included-1h0h"&gt;link&lt;/a&gt; · Part 2 (&lt;code&gt;--from-database&lt;/code&gt;): &lt;a href="https://dev.to/nameless0l/turning-an-existing-database-into-a-documented-laravel-api-2eia"&gt;link&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have opinions about what a schema format should support, the issues are open. Mine changed three times while building this.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>architecture</category>
      <category>api</category>
    </item>
    <item>
      <title>Turning an existing database into a documented Laravel API</title>
      <dc:creator>Loic Aron Mbassi Ewolo</dc:creator>
      <pubDate>Wed, 22 Jul 2026 11:04:16 +0000</pubDate>
      <link>https://dev.to/nameless0l/turning-an-existing-database-into-a-documented-laravel-api-2eia</link>
      <guid>https://dev.to/nameless0l/turning-an-existing-database-into-a-documented-laravel-api-2eia</guid>
      <description>&lt;p&gt;The projects I dread are the ones where the database is the only documentation. Twenty tables, foreign keys, years of production data, and either no API layer at all or a pile of copy-pasted controllers nobody wants to touch.&lt;/p&gt;

&lt;p&gt;Writing models, controllers, validation and tests for twenty existing tables by hand takes days. This is the problem that made me add &lt;code&gt;--from-database&lt;/code&gt; to &lt;a href="https://github.com/Nameless0l/laravel-api-generator" rel="noopener noreferrer"&gt;laravel-api-generator&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require &lt;span class="nt"&gt;--dev&lt;/span&gt; nameless/laravel-api-generator
php artisan make:fullapi &lt;span class="nt"&gt;--from-database&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The generator reads your live schema and produces, for each table, the same stack it builds in normal mode: model with full PHPDoc, thin controller, service, DTO, form requests with real validation rules, resource, factory, seeder, policy, and written tests (PHPUnit, or Pest with &lt;code&gt;--pest&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;[GIF demo-from-database.gif (voir fichier 12) : vraie exécution en terminal, pas Claude Design]&lt;/p&gt;

&lt;h2&gt;
  
  
  What the introspection actually reads
&lt;/h2&gt;

&lt;p&gt;I spent a lot of time making this more than a column dump.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;VARCHAR(255) NOT NULL UNIQUE&lt;/code&gt; column doesn't just become a &lt;code&gt;string&lt;/code&gt; field. It becomes &lt;code&gt;required|string|max:255|unique:users,email&lt;/code&gt; in the form request and &lt;code&gt;fake()-&amp;gt;unique()-&amp;gt;safeEmail()&lt;/code&gt; in the factory.&lt;/p&gt;

&lt;p&gt;Foreign keys turn into relations on both sides: &lt;code&gt;posts.user_id&lt;/code&gt; gives you &lt;code&gt;Post::user(): BelongsTo&lt;/code&gt; and &lt;code&gt;User::posts(): HasMany&lt;/code&gt;, both typed in the PHPDoc. On Laravel 11+ the generator reads the real constraints; it also falls back to the &lt;code&gt;&amp;lt;table&amp;gt;_id&lt;/code&gt; naming convention for older schemas without them.&lt;/p&gt;

&lt;p&gt;Pivot tables are detected (two foreign keys and nothing else) and become &lt;code&gt;belongsToMany&lt;/code&gt; on both models, instead of generating a useless &lt;code&gt;PostTag&lt;/code&gt; entity. Column pairs like &lt;code&gt;commentable_type&lt;/code&gt; + &lt;code&gt;commentable_id&lt;/code&gt; become a proper &lt;code&gt;morphTo&lt;/code&gt;. Enum columns become native PHP backed enums with casts and &lt;code&gt;Rule::enum&lt;/code&gt; validation. A &lt;code&gt;deleted_at&lt;/code&gt; column switches the whole entity to soft deletes, restore endpoint included.&lt;/p&gt;

&lt;h2&gt;
  
  
  You rarely want all tables
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan make:fullapi &lt;span class="nt"&gt;--from-database&lt;/span&gt; &lt;span class="nt"&gt;--tables&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;posts,categories,comments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two defaults exist to save you from yourself: migrations are not regenerated (the tables already exist; pass &lt;code&gt;--with-migrations&lt;/code&gt; if you want them as code-of-record), and the &lt;code&gt;users&lt;/code&gt; table is skipped so your customized &lt;code&gt;User.php&lt;/code&gt; survives. &lt;code&gt;--tables=users&lt;/code&gt; overrides that explicitly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The payoff
&lt;/h2&gt;

&lt;p&gt;The generated controllers are Scramble-friendly, so if you have &lt;a href="https://scramble.dedoc.co" rel="noopener noreferrer"&gt;Scramble&lt;/a&gt; installed, &lt;code&gt;/docs/api&lt;/code&gt; serves browsable OpenAPI docs immediately. Add &lt;code&gt;--postman&lt;/code&gt; and you can hand a collection to the frontend team the same morning.&lt;/p&gt;

&lt;p&gt;If the team lives in VS Code, the &lt;a href="https://marketplace.visualstudio.com/items?itemName=Nameless0l.laravel-api-generator" rel="noopener noreferrer"&gt;extension&lt;/a&gt; runs the same import from a table picker, and its &lt;strong&gt;Open API Docs&lt;/strong&gt; button closes the loop: it checks Scramble, starts the server if none is running, detects the port and opens the docs in the browser. It even offers to create &lt;code&gt;.env&lt;/code&gt; from &lt;code&gt;.env.example&lt;/code&gt; on a fresh checkout.&lt;/p&gt;

&lt;p&gt;Legacy database at 9:00, documented and tested API at 9:15. The business logic still needs a human. The plumbing doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes
&lt;/h2&gt;

&lt;p&gt;The package is a &lt;code&gt;--dev&lt;/code&gt; dependency and the generated code doesn't depend on it, so you can treat it as a one-shot migration tool if that's all you need.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docs: &lt;a href="https://nameless0l.github.io/laravel-api-generator/" rel="noopener noreferrer"&gt;https://nameless0l.github.io/laravel-api-generator/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Part 1, on the architecture it generates: &lt;a href="https://dev.to/nameless0l/a-complete-laravel-api-with-clean-architecture-in-30-seconds-tests-included-1h0h"&gt;part1&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have a schema that you think would break it, I want to see it. Weird databases are how this feature got better.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>database</category>
      <category>api</category>
    </item>
    <item>
      <title>A complete Laravel API with clean architecture in 30 seconds, tests included</title>
      <dc:creator>Loic Aron Mbassi Ewolo</dc:creator>
      <pubDate>Sat, 18 Jul 2026 20:23:24 +0000</pubDate>
      <link>https://dev.to/nameless0l/a-complete-laravel-api-with-clean-architecture-in-30-seconds-tests-included-1h0h</link>
      <guid>https://dev.to/nameless0l/a-complete-laravel-api-with-clean-architecture-in-30-seconds-tests-included-1h0h</guid>
      <description>&lt;p&gt;I counted the files I create every time I add a resource to a Laravel API. Model, migration, controller, a form request, a resource, a factory, a seeder, a policy. If the project cares about architecture, add a DTO and a service class. Then the tests.&lt;/p&gt;

&lt;p&gt;Twelve files before the first line of actual business logic. I got tired of typing them, so I wrote a generator. It's MIT, I maintain it solo, and v3.6 shipped this week.&lt;/p&gt;

&lt;h2&gt;
  
  
  One command
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require &lt;span class="nt"&gt;--dev&lt;/span&gt; nameless/laravel-api-generator

php artisan make:fullapi Post &lt;span class="nt"&gt;--fields&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"title:string,content:text,status:enum(draft,published),published_at:datetime"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app/
├── DTO/PostDTO.php
├── Enums/Status.php
├── Http/
│   ├── Controllers/PostController.php
│   ├── Requests/PostRequest.php
│   └── Resources/PostResource.php
├── Models/Post.php
├── Policies/PostPolicy.php
└── Services/PostService.php
database/
├── factories/PostFactory.php
├── migrations/xxxx_create_posts_table.php
└── seeders/PostSeeder.php
tests/
├── Feature/PostControllerTest.php
└── Unit/PostServiceTest.php
routes/api.php  ← apiResource registered
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;[GIF demo.gif (voir fichier 12) : vraie exécution en terminal, pas Claude Design]&lt;/p&gt;

&lt;h2&gt;
  
  
  The VS Code extension: same engine, no terminal needed
&lt;/h2&gt;

&lt;p&gt;[VISUEL 11 (fichier 13) : VRAI screenshot de l'extension VS Code, habillé ensuite dans Claude Design]&lt;/p&gt;

&lt;p&gt;If you'd rather click than type, the free &lt;a href="https://marketplace.visualstudio.com/items?itemName=Nameless0l.laravel-api-generator" rel="noopener noreferrer"&gt;VS Code extension&lt;/a&gt; drives the same &lt;code&gt;make:fullapi&lt;/code&gt; command, so the files are identical. You describe the entity in a form (fields, enums, relations, options) and a live preview shows the exact code before anything is written. Or you skip the form and import from your existing database, a YAML schema, a Mermaid diagram, or an OpenAPI/Swagger spec.&lt;/p&gt;

&lt;p&gt;The button I always demo first is &lt;strong&gt;Open API Docs&lt;/strong&gt;: it checks that Scramble is installed (and offers to install it if not), finds a running Laravel server or starts &lt;code&gt;php artisan serve&lt;/code&gt; itself, detects the port, and opens the interactive docs of your new API in the browser. Migrations and seeding are one-click too, and if &lt;code&gt;.env&lt;/code&gt; is missing the extension offers to create it from &lt;code&gt;.env.example&lt;/code&gt;. You can go from an empty Laravel project to a browsable, documented, tested API without opening a terminal once.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwsl2r44almbl3aqu5nfv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwsl2r44almbl3aqu5nfv.png" alt="scramble image" width="799" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I actually care about: the architecture
&lt;/h2&gt;

&lt;p&gt;Plenty of tools can spit out a model and a migration. What I wanted was the layering I end up building by hand on every serious project. The generated controller is thin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;PostRequest&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$dto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PostDTO&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;fromRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$dto&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PostResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Validation lives in the form request, business logic in &lt;code&gt;PostService&lt;/code&gt;, and data crosses layers as a typed readonly &lt;code&gt;PostDTO&lt;/code&gt;. When the project grows, the place where new logic should go already exists. That's the whole point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Models your IDE can read
&lt;/h2&gt;

&lt;p&gt;Each generated model comes with a real PHPDoc block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @property int $id
 * @property string $title
 * @property string $content
 * @property Status $status
 * @property \Illuminate\Support\Carbon|null $published_at
 * @property-read \Illuminate\Database\Eloquent\Collection&amp;lt;int, Comment&amp;gt; $comments
 */&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So &lt;code&gt;$post-&amp;gt;title&lt;/code&gt; autocompletes in VS Code and PhpStorm without installing ide-helper. The generator already knows every field and relation at generation time; writing the docblock costs it nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What &lt;code&gt;enum(draft,published)&lt;/code&gt; produced
&lt;/h2&gt;

&lt;p&gt;That one field definition created five coherent pieces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;App\Enums\Status&lt;/code&gt;, a native backed enum&lt;/li&gt;
&lt;li&gt;the cast on the model&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Rule::enum(Status::class)&lt;/code&gt; in both form requests&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fake()-&amp;gt;randomElement(Status::cases())&lt;/code&gt; in the factory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$table-&amp;gt;enum('status', [...])&lt;/code&gt; in the migration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before v3.6 the package just mapped enums to strings. Wiring the whole chain took longer than I expected, mostly because of the factory.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tests are written, not scaffolded
&lt;/h2&gt;

&lt;p&gt;This was my line in the sand. Most generators leave you empty test classes. Here &lt;code&gt;php artisan test&lt;/code&gt; is green right after generation: index, store, validation errors, update, delete are all covered with real assertions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'creates a post'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;postJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/api/posts'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertCreated&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertDatabaseHas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'posts'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'title'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'title'&lt;/span&gt;&lt;span class="p"&gt;]]);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the Pest style, from the &lt;code&gt;--pest&lt;/code&gt; flag. Without it you get PHPUnit classes with the same coverage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docs, Postman, auth
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;--postman&lt;/code&gt; writes a ready-to-import collection at the project root. The controllers are written so &lt;a href="https://scramble.dedoc.co" rel="noopener noreferrer"&gt;Scramble&lt;/a&gt; can build OpenAPI docs from them without annotations. &lt;code&gt;--auth&lt;/code&gt; scaffolds Sanctum (register, login, logout, middleware on your resources).&lt;/p&gt;

&lt;p&gt;There is also a &lt;code&gt;--from-database&lt;/code&gt; mode that reverse-engineers an existing database into full APIs, but that deserves its own article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Zero lock-in
&lt;/h2&gt;

&lt;p&gt;The package installs with &lt;code&gt;--dev&lt;/code&gt; and the generated code has no dependency on it. No base classes, no runtime helpers, nothing to &lt;code&gt;use&lt;/code&gt;. You can remove the generator after generating and the app doesn't notice. If you don't like the generated style, publish the 24 stubs (&lt;code&gt;php artisan vendor:publish --tag=api-generator-stubs&lt;/code&gt;) and edit whichever ones you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it stops
&lt;/h2&gt;

&lt;p&gt;It scaffolds a clean REST baseline and then it's out of the picture. Your domain logic, your weird queries, your edge cases: still your job. The difference is that you write them inside a service layer that already exists, with baseline tests already passing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require &lt;span class="nt"&gt;--dev&lt;/span&gt; nameless/laravel-api-generator
php artisan make:fullapi Product &lt;span class="nt"&gt;--fields&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"name:string,price:decimal,stock:integer"&lt;/span&gt; &lt;span class="nt"&gt;--pest&lt;/span&gt;
php artisan &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Docs: &lt;a href="https://nameless0l.github.io/laravel-api-generator/" rel="noopener noreferrer"&gt;https://nameless0l.github.io/laravel-api-generator/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/Nameless0l/laravel-api-generator" rel="noopener noreferrer"&gt;https://github.com/Nameless0l/laravel-api-generator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;VS Code extension: &lt;a href="https://marketplace.visualstudio.com/items?itemName=Nameless0l.laravel-api-generator" rel="noopener noreferrer"&gt;https://marketplace.visualstudio.com/items?itemName=Nameless0l.laravel-api-generator&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you try it and something breaks, open an issue. Schema edge cases reported by users have driven most of the recent releases, and I'd rather hear about yours than guess.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
