Skip to content

Leaf MVC for APIs

Leaf MVC is a minimalistic PHP framework built for developers who need a simple and elegant toolkit to create full-featured web applications.

You might choose to separate your API logic from your frontend, with a mobile app or a framework like React, Vue, or Svelte consuming your API. This approach keeps things modular, letting you build once and serve multiple clients.

While you can build APIs with the basic Leaf setup, Leaf MVC provides a structured way to do it. It follows the Model-View-Controller (MVC) pattern, but instead of traditional views, you return JSON or XML responses—keeping things clean, simple, and fast. And, of course, you still get all the power and flexibility Leaf brings.

Getting started

You can create a new MVC API app using the create command on the Leaf CLI.

Leaf CLI
bash
leaf create my-app --api

This command sets up a new Leaf MVC app in the my-app directory, optimized for building APIs. It removes default views, configures JSON responses by default, and includes a few console tweaks to streamline API development. Once it's ready, navigate to your app directory and start the server.

bash
cd my-app
php leaf serve

Your app is now running! Open http://localhost:5500 in your browser.

Project Structure

Leaf MVC, like the rest of Leaf, is built for makers—focused, lightweight, and flexible. It keeps only the essentials, giving you everything you need without the extra baggage. Here’s the basic structure of a Leaf MVC app:

bash
├───app
   ├── controllers
   ├── database
   ├── models
   └── routes
└───public

Leaf MVC keeps things simple, ensuring you focus on building rather than configuration. Here’s a quick breakdown of the key directories:

  • app/ – This is where all your application logic lives, including controllers, models, views, and routes. Your database files also reside here.
  • public/ – Contains publicly accessible files like images. This is the only directory exposed to the browser.

Most of your work will happen in the app directory, with a typical request starting with a route, which calls a controller, which interacts with a model, and finally renders a view—this is the MVC cycle in action.

Don’t worry if you’re new to MVC! Just remember: every request starts with a route and ends with a JSON or XML response.

Building your first app

As a maker, the easiest way to get started with your app is by building a Coming Soon, Early Access, or Pre-Launch page. This gives you something real to share while you build, helping you gather interest and early users. Let’s create a simple API that collects emails for a pre-launch page.

1 The routing bit

In Leaf MVC, routes are defined in the app/routes directory. You’ll find an index.php file along with some files that start with _. These are partials, and Leaf automatically loads them to help you organize routes in a way that fits your project.

For our pre-launch page, let’s create a new route inside app/routes/_prelaunch.php. Open the file and add this:

php
<?php

app()->post('/prelaunch', 'SubscribersController@store');

Okay, let's break it down:

  • app() is a helper function that gives you access to the Leaf app instance, it is available from anywhere in your app.
  • post() is a method that limits the route to POST requests only. The first argument is the route, and the second is the controller and method that will handle the request.

2 Handling the form submission

This is the most important piece of our pre-launch API. We need to create a route that calls a controller, validates the email, and saves it to a database using a model. This will take us through the full MVC cycle, plus a bit of setup.

Let’s start by generating the controller we defined in our route, we'll use the console for this:

bash
php leaf g:controller subscribers

This will create a new controller in the app/controllers directory. Open the SubscribersController.php file and add the store method.

app/controllers/SubscribersController.php
php
<?php

namespace App\Controllers;

class SubscribersController extends Controller
{
    public function store() 
    { 
        // handle the email //
    } 
}

We're almost there! We need to validate the email and save it to a database. Validation is pretty simple with Leaf, we can use the validate() method on our request and pass in the rules we want to validate against.

app/controllers/SubscribersController.php
php
<?php

namespace App\Controllers;

class SubscribersController extends Controller
{
    public function store()
    {
        if (!$data = request()->validate(['email' => 'email'])) { 
            return response()->json(['status' => 'error', 'data' => request()->errors()], 400); 
        } 

        // save the email
    }
}

This validates the entered email and returns an error if it's not a valid email. Great job so far! Now, let's save the email to a database using a model.

3 Working with the database

First, we'll generate a Subscriber model using the console:

bash
php leaf g:model subscriber

We don’t need to modify the model—Leaf keeps things simple. But before we can store anything, we need to connect our database. Open your .env file and add your database credentials:

env
DB_CONNECTION=mysql
DB_HOST=xxx
DB_PORT=xxx
DB_DATABASE=xxx
DB_USERNAME=xxx
DB_PASSWORD=xxx

After updating your credentials, restart your server with: php leaf serve.

Now, we need to create our database table. Leaf MVC makes this seamless with schema files, a simpler way to define and manage your database structure. Let’s set up our schema next!

bash
php leaf g:schema subscribers

The name of the schema file should be the same as your table name. This will create a new schema file in the app/database directory. Open the file and add the columns you want in your table.

app/database/subscribers.yml
php
columns:
  email: string

Here, we are telling Leaf to add a column where we can store the email. We can now run the migration to create the table.

bash
php leaf db:migrate

4 Saving the email

We can now save the email to the database using our Subscriber model.

app/controllers/SubscribersController.php
php
<?php

namespace App\Controllers;

use App\Models\Subscriber;  

class SubscribersController extends Controller
{
    public function store()
    {
        if (!$data = request()->validate(['email' => 'email'])) {
            return response()->json(['status' => 'error', 'data' => request()->errors()], 400);
        }

        $subscriber = new Subscriber;  
        $subscriber->email = $data['email'];  
        $subscriber->save();  

        return response()->json([ 
          'status' => 'success', 
          'data' => $data
        ]);  
    }
}

We can now test this by sending a POST request to http://localhost:5500/prelaunch with an email parameter. If everything is set up correctly, you should see a success message with the email you sent.

5 Deploying your app

We have built a simple pre-launch page using Leaf MVC. You can now deploy your app to a server using a service like Heroku, Fly.io a VPS like DigitalOcean, or even a shared hosting service like Sevalla.

For your frontend app, you can consider managed services like Netlify, Vercel, or GitHub Pages which offer one-click deployments.

Are you stuck? Working with MVC can be a bit challenging if you are just starting out because of the overly strict separation of concerns. If you are stuck at any point, feel free to ask for help in the Leaf Discord server, or consider building an MVP using the Basic Leaf setup. While it is not as structured as MVC, it is a great way to get started with Leaf.

Now that you have built a simple pre-launch page, the next step is to get you familiar with the basics of building a full-stack application with Leaf. So you can build and launch your next big idea fast.

  • Routing

    Learn more about routing in Leaf MVC, dynamic routes, middleware and more.

  • Using Controllers

    Controllers are the 'C' in MVC, and separate your logic from your views.

  • Using Models

    Models are the 'M' in MVC, and let you interact with your database programmatically.

  • Authentication

    Learn about signing users in and out, user management, roles + permissions, and more.

Released under the MIT License.