Skip to main content
Laravel, shipping fast.
Chapter 1 · Getting Started

The Structure You Already Know

Julian Beaujardin

A Laravel 13 application is small when it is new. Folders appear as you ask Artisan for things, and each one has a single job:

app/Http/Controllers/   make:controller   HTTP in, HTTP out
app/Http/Requests/      make:request      validation
app/Http/Resources/     make:resource     JSON output
app/Http/Middleware/    make:middleware   request pipeline
app/Jobs/               make:job          work for the queue
app/Providers/          make:provider     container bindings
routes/api.php                            the endpoints
tests/Feature/          make:test         full request tests

This API adds two folders that no Artisan command creates:

app/Services/License/   the integration with Statamic
app/Facades/            the name the application calls it by

Chapter 3 explains both. Everything else stays where a Laravel developer expects to find it. When someone new joins the team and opens the project, they should think “I’ve seen this before.” That reaction is worth more than any structure you could invent.

The Endpoint Laravel Gives You

Before writing anything, look at what is already there. Open bootstrap/app.php:

->withRouting(
    api: __DIR__.'/../routes/api.php',
    commands: __DIR__.'/../routes/console.php',
    health: '/up',
)

That health line is a working health check. GET /up returns a 200 when the application boots and a 500 when it doesn’t, which is what a load balancer needs to know. You didn’t write it and you don’t maintain it. Chapter 13 extends it to check the database and the cache. (Laravel documentation: Deployment › The Health Route.)

Make this a habit: before you build something, check whether Laravel already ships it.

Your First Endpoint

The first real endpoint lists licenses. Here is the version that takes five minutes:

// routes/api.php
Route::get('/licenses', function () {
    $token = config('services.statamic.token');

    return Http::withToken($token)
        ->get('https://statamic.com/api/v1/sites')
        ->json('data');
});

It works. You could demo it today. It is also a list of problems waiting for a second endpoint:

  • It returns whatever Statamic returns. If the provider adds a field tomorrow, your API exposes it tomorrow. Your consumers are now coupled to a company they have never heard of.
  • Nothing checks what came back. A missing key or a null travels straight through to the client.
  • The provider is welded into the route. The URL, the token, and the HTTP call sit in the one place that should only know about HTTP.
  • You can’t test it without calling Statamic or faking it by hand in every test.
  • The next endpoint will copy it. And the third will copy it slightly differently.

None of this makes the quick version wrong. It makes it a prototype. Here is the same endpoint the way the rest of this book builds them:

// routes/api.php
Route::apiResource('licenses', LicenseController::class)
    ->only(['index', 'store', 'destroy']);
// app/Http/Controllers/LicenseController.php
public function index(): AnonymousResourceCollection
{
    return LicenseResource::collection(Licenses::all());
}

One line of routing declares all three endpoints with the names and verbs every Laravel developer already knows: GET /licenses is index, POST /licenses is store, DELETE /licenses/{license} is destroy. (Laravel documentation: Controllers › API Resource Routes.)

The controller method is one line too, and each part of it answers one of the problems above. Licenses::all() hides the provider behind an interface and returns typed objects, so nothing malformed gets past it. LicenseResource decides which fields leave the API, so the provider’s shape never leaks. The controller knows about HTTP and nothing else.

There is no magic here, only a few more files. The next two chapters build each of them.

Principles for Shipping Fast

Five principles run through the rest of the book.

Convention over configuration. Laravel’s conventions are distilled from thousands of production applications. Default to Laravel’s way, and step outside it only when you have a specific reason you can write down. This book does step outside in a few places, and each time it says why.

Consistency over novelty. Every endpoint should look like the one before it. Validation in a FormRequest, output through a Resource, the provider behind an interface. When something has to change, it changes in one place.

Types at the boundaries. Use type hints and return types, and run static analysis at a level your team will keep green. The places that matter most are the edges, where data arrives from a client or from a provider. Once a value has a type, the rest of the code can trust it.

Fail fast. Validate input before the controller runs. Reject a malformed provider response where it arrives, instead of letting a bad value travel inward and fail far from its cause.

Test as you build. Not after, and not someday. A test written with the endpoint catches the mistake while you still remember what you meant.

Security belongs on that list too, and it runs through the whole book: authentication in Chapter 4, authorization on records in Chapter 5, the request pipeline in Chapter 6, and a review of all of it in Chapter 19.

Chapter 1 Summary

  • The License API manages licenses that live at an external provider. It has no table of its own for them.
  • Start with install:api, and let Artisan create the folders.
  • Before building something, check whether Laravel already ships it. The health route is the first example.
  • A route closure that calls the provider is a prototype. A resourceful route, a thin controller, a Resource, and a facade are the version that lasts.
  • Convention, consistency, types at the boundaries, failing fast, and tests written with the code.

The audio could not be loaded. Try again in a moment.