<?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>I gave my Laravel API generator an MCP server</title>
      <dc:creator>Loic Aron Mbassi Ewolo</dc:creator>
      <pubDate>Tue, 29 Sep 2026 11:06:34 +0000</pubDate>
      <link>https://dev.to/nameless0l/i-gave-my-laravel-api-generator-an-mcp-server-53je</link>
      <guid>https://dev.to/nameless0l/i-gave-my-laravel-api-generator-an-mcp-server-53je</guid>
      <description>&lt;p&gt;Coding agents write Laravel code well. Ask one for a CRUD API and it will write the model, controller, requests, resource, policy, migration, factory, seeder and tests by hand, slightly differently every time, and you get to review all of it.&lt;/p&gt;

&lt;p&gt;I maintain &lt;a href="https://github.com/Nameless0l/laravel-api-generator" rel="noopener noreferrer"&gt;Laravel API Generator&lt;/a&gt;, a dev-only package that writes those files from a schema, with tests that pass and code that passes Pint. Version 4.0 gives it an MCP server, so the agent calls the generator instead of typing the files.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/bRK9Y8jn7yY" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Two commands
&lt;/h2&gt;

&lt;p&gt;The server runs on &lt;a href="https://laravel.com/docs/mcp" rel="noopener noreferrer"&gt;Laravel MCP&lt;/a&gt;, which needs Laravel 12.41 or later.&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 laravel/mcp
claude mcp add &lt;span class="nt"&gt;-s&lt;/span&gt; project laravel-api-generator &lt;span class="nt"&gt;--&lt;/span&gt; php artisan api-generator:mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;-s project&lt;/code&gt;, Claude Code writes &lt;code&gt;.mcp.json&lt;/code&gt;, which you can commit so the whole team gets the server. Cursor and other clients take the same command, &lt;code&gt;php artisan api-generator:mcp&lt;/code&gt;, and in VS Code the extension registers it for Copilot's agent mode on its own.&lt;/p&gt;

&lt;p&gt;The agent gets four tools:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;list-entities&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Returns each generated entity with its files, marked intact, edited or missing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;plan-api&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lists every file a generation would create or update, with warnings, without writing anything&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generate-api&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Writes the files, from an api-schema document or an OpenAPI spec of the project&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;add-fields&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Adds columns to an entity, with an incremental migration and in-place patches&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The first two are marked read-only, so your client knows they change nothing. The server also ships a &lt;code&gt;design-api&lt;/code&gt; prompt, which Claude Code offers as a slash command, and exposes the JSON Schema of the schema format as a resource.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plan first
&lt;/h2&gt;

&lt;p&gt;Here is the run from the video: &lt;code&gt;/mcp__laravel-api-generator__design-api&lt;/code&gt; with one sentence, &lt;em&gt;a library that lends books to members&lt;/em&gt;. The agent checked what already existed, drafted a schema and called &lt;code&gt;plan-api&lt;/code&gt;.&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%2F1uxrtjqdl0ptko4api7a.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%2F1uxrtjqdl0ptko4api7a.png" alt="Claude Code proposing 4 entities and 56 files before writing anything" width="800" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Four entities, 56 files, no warnings, and a question at the end: generate it as is, or change something first? After the go, &lt;code&gt;generate-api&lt;/code&gt; wrote everything and the 62 generated tests passed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your edits stay yours
&lt;/h2&gt;

&lt;p&gt;The package records every file it writes in &lt;code&gt;.api-generator/manifest.json&lt;/code&gt;. A file you changed since is reported as edited, and &lt;code&gt;generate-api&lt;/code&gt; leaves it as it is (&lt;code&gt;"kept": true&lt;/code&gt; in the result). The server never deletes a file and never runs a migration. Overwriting your edits with &lt;code&gt;--force&lt;/code&gt;, deleting an entity and migrating stay on the command line.&lt;/p&gt;

&lt;p&gt;In the demo, &lt;code&gt;LoanService.php&lt;/code&gt; got a hand-written rule. Asked for a &lt;code&gt;notes&lt;/code&gt; field on loans, the agent read the manifest, saw the edited service, ran &lt;code&gt;add-fields&lt;/code&gt; as a dry run first, and the service came out untouched.&lt;/p&gt;

&lt;p&gt;One gap showed up while filming: &lt;code&gt;add-fields&lt;/code&gt; doesn't update the DTO yet, so the agent patched &lt;code&gt;LoanDTO.php&lt;/code&gt; itself. That's the next fix on my list.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the generated code looks like in 4.0
&lt;/h2&gt;

&lt;p&gt;4.0 is a major release because the output changed. It needs Laravel 12 or 13, while Laravel 10 and 11 stay on the 3.x line.&lt;/p&gt;

&lt;p&gt;Controllers bind the model from the route and start every action with the policy:&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;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UpdateArticleRequest&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Article&lt;/span&gt; &lt;span class="nv"&gt;$article&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Gate&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;authorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'update'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$article&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;ArticleDTO&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArticleResource&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="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$article&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The update rules start with &lt;code&gt;sometimes&lt;/code&gt;, and the DTO remembers which keys the request sent, so a PATCH with a single field changes that field and nothing else. The index is paginated, filtered and sorted out of the box:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/articles?filter[status]=published&amp;amp;sort=-created_at&amp;amp;per_page=20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Laravel 13, models declare their fillable columns with &lt;code&gt;#[Fillable]&lt;/code&gt;. Enums are named after the entity and the field (&lt;code&gt;ArticleStatus&lt;/code&gt;), and every generated file passes &lt;code&gt;pint --test&lt;/code&gt; with the Laravel preset, which the CI checks on both Laravel versions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The VS Code extension, redesigned
&lt;/h2&gt;

&lt;p&gt;Not everyone drives an agent. The &lt;a href="https://marketplace.visualstudio.com/items?itemName=Nameless0l.laravel-api-generator" rel="noopener noreferrer"&gt;VS Code extension&lt;/a&gt; does the same work with a form, and 1.1 redesigns it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fskykeqloas7zbau1r8ig.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fskykeqloas7zbau1r8ig.gif" alt="Pick an example, add a relation, and the live preview follows" width="760" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The preview on the right comes from the package installed in your project, through a long-running &lt;code&gt;php artisan api-generator:serve --stdio&lt;/code&gt;, so it shows exactly the files that will be written, diffs included. A database, a schema file, a Mermaid diagram, an OpenAPI spec and a plain description drafted by Copilot all end on the same review screen before anything is written.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foo02c2vwurejnh1n05og.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foo02c2vwurejnh1n05og.gif" alt="The review of an OpenAPI spec, then the generation" width="760" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After a generation, the panel runs the next steps in place: migrations, tests, seeding and the Scramble docs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fctlq57u2ab9x2v5ovvph.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fctlq57u2ab9x2v5ovvph.gif" alt="One click on Generate, then the migrations and the tests" width="760" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's also on &lt;a href="https://open-vsx.org/extension/Nameless0l/laravel-api-generator" rel="noopener noreferrer"&gt;Open VSX&lt;/a&gt; for Cursor and VSCodium.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it doesn't do
&lt;/h2&gt;

&lt;p&gt;It generates code, and that's all. Autocompletion and navigation for Eloquent and Blade are the job of the official Laravel extension. The MCP server needs Laravel 12.41 or later. And the output is opinionated, with a thin controller, a service and a DTO: if your team writes CRUD differently, &lt;a href="https://nameless0l.github.io/laravel-api-generator/guide/customizing-stubs" rel="noopener noreferrer"&gt;publish the stubs&lt;/a&gt; and change them, and &lt;code&gt;api-generator:validate-stubs&lt;/code&gt; checks them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&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;MCP setup for Cursor, Docker and Sail: &lt;a href="https://nameless0l.github.io/laravel-api-generator/guide/mcp" rel="noopener noreferrer"&gt;https://nameless0l.github.io/laravel-api-generator/guide/mcp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Upgrading from 3.x: &lt;a href="https://nameless0l.github.io/laravel-api-generator/guide/upgrading" rel="noopener noreferrer"&gt;https://nameless0l.github.io/laravel-api-generator/guide/upgrading&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Package: &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;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;It's free and MIT. If you try it on a real schema, tell me what breaks, here or in an issue.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>ai</category>
      <category>mcp</category>
    </item>
    <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>
