DEV Community

n0nag0n
n0nag0n

Posted on • Edited on

Creating a RESTful API with Flight Framework

In this article, we'll walk through building a RESTful API using the Flight framework, which is a simple yet powerful PHP micro-framework. Flight aims to be simple to understand what is going on with your application and leave you in control without too much "magic" happening. We'll cover the basics of setting up the framework, creating a user resource in a SQLite database, and implementing a simple authentication middleware.

Getting Started with Flight

First, let's set up Flight and create our project. You can download Flight from its GitHub repository or installed via composer. Composer is generally the way to go.

Installation

You can install Flight via Composer. Create a new directory for your project and run the following command:

composer require flightphp/core
Enter fullscreen mode Exit fullscreen mode

Setting Up Your Project

Here is the example directory structure for your project:

project-root/
├── public/
│   └── index.php
├── config/
│   └── config.php
├── middleware/
│   └── AuthMiddleware.php
├── vendor/
└── composer.json
Enter fullscreen mode Exit fullscreen mode

Create an index.php file in your public directory. This file will serve as the entry point for your application.

<?php
require __DIR__.'/../vendor/autoload.php';

Flight::route('/', function(){
    echo 'Hello, world!';
});

Flight::start();
Enter fullscreen mode Exit fullscreen mode

Open up your terminal application and type php -S localhost:8080 -t public/ and navigate to http://localhost:8080 to see the "Hello, world!" message. If you get an error message about a port already being used, go ahead and try another port like 8081.

Creating the User Resource

Now, let's create a user resource with CRUD operations. We'll use SQLite for the database for the simplicity of this tutorial, but you can use any database of your choice.

Database Connection

Create a config.php file to store your database credentials:

<?php
// config.php
return [
    'database_path' => __DIR__.'/../flight_app.sqlite',
];
Enter fullscreen mode Exit fullscreen mode

CRUD Operations

In your index.php file, include the database connection and define CRUD operations for the user resource.

<?php
require __DIR__.'/../vendor/autoload.php';
$config = require __DIR__.'/../config/config.php';

// This is where you can register a database connection so you can use it in any of your routes below
Flight::register('db', \flight\database\PdoWrapper::class, [ 'sqlite:'.$config['database_path'] ], function($db){
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
});

// This will create the database and the users table if it doesn't exist already
if(file_exists($config['database_path']) === false) {
    $db = Flight::db();
    $db->runQuery("CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT NOT NULL UNIQUE, password TEXT NOT NULL)");
}

// A group helps group together similar routes for convenience
Flight::group('/users', function(\flight\net\Router $router) {

    // Get all users
    $router->get('', function(){
        $db = Flight::db();
        $users = $db->fetchAll("SELECT * FROM users");
        Flight::json($users);
    });

    // Get user by id
    $router->get('/@id', function($id){
        $db = Flight::db();
        $user = $db->fetchRow("SELECT * FROM users WHERE id = :id", [ ':id' => $id ]);
        if (!empty($user['id'])) {
            Flight::json($user);
        } else {
            Flight::jsonHalt([ 'message' => 'User not found' ], 404);
        }
    });

    // Create new user
    $router->post('', function(){
        $data = Flight::request()->data;
        $db = Flight::db();
        $result = $db->runQuery("INSERT INTO users (name, email, password) VALUES (:name, :email, :password)", [ 
            ':name' => $data['name'], 
            ':email' => $data['email'], 
            ':password' => password_hash($data['password'], PASSWORD_BCRYPT) 
        ]);
        Flight::json([ 'id' => $db->lastInsertId() ], 201);
    });

    // Update user
    $router->put('/@id', function($id){
        $data = Flight::request()->data->getData();
        $db = Flight::db();
        $result = $db->runQuery("UPDATE users SET name = :name, email = :email, password = :password WHERE id = :id", [
            ':id' => $id,
            ':name' => $data['name'],
            ':email' => $data['email'],
            ':password' => password_hash($data['password'], PASSWORD_BCRYPT)
        ]);
        Flight::json([ 'message' => 'User updated successfully' ]);
    });

    // Delete user
    $router->delete('/@id', function($id){
        $db = Flight::db();
        $stmt = $db->runQuery("DELETE FROM users WHERE id = :id", [ ':id' => $id ]);
        Flight::json([ 'message' => 'User deleted successfully' ]);
    });

});

Flight::start();
Enter fullscreen mode Exit fullscreen mode

Simple Authentication Middleware

Next, let's implement a simple authentication middleware to protect our API routes.

Create a new file called AuthMiddleware.php:

<?php
// AuthMiddleware.php

class AuthMiddleware {

    public function before() {
        $headers = Flight::request()->getHeaders();
        if (isset($headers['Authorization']) === true) {
            $token = $headers['Authorization'];
            // Normally, you would validate the token here. For simplicity, we'll just check if it's "secret"
            if ($token == 'secret') {
                return true;
            }
        }
        Flight::jsonHalt([ 'message' => 'Unauthorized' ], 401);
    }

}
Enter fullscreen mode Exit fullscreen mode

Include this middleware in your index.php file and protect your routes:

<?php
require __DIR__.'/../vendor/autoload.php';
$config = require __DIR__.'/../config/config.php';
require __DIR__.'/../middleware/AuthMiddleware.php';

// code to set up database connection (as shown above)

Flight::group('/users', function(\flight\net\Router $router) {

    // previously defined routes here

// This is where you put the middleware
}, [ new AuthMiddleware() ]);

// Repeat for other routes...
Enter fullscreen mode Exit fullscreen mode

Example Usage

To test your API, you can use tools like Postman or cURL. Here’s an example using cURL to get all users:

Creating a User

curl -X POST -H "Authorization: secret" -d '{"name":"John Doe", "email":"john@example.com", "password":"password"}' http://localhost:8080/users
Enter fullscreen mode Exit fullscreen mode

This will create a new user and return the user ID.

Getting All Users

curl -H "Authorization: secret" http://localhost:8080/users
Enter fullscreen mode Exit fullscreen mode

This will return a JSON response with all the users in your database.

Getting a User by ID

Now that you have created a user, you can get the user by ID. You can get the ID from the response of the previous request.

curl -H "Authorization: secret" http://localhost:8080/users/1
Enter fullscreen mode Exit fullscreen mode

Updating a User

You can update a user by sending a PUT request with the user ID and the updated data.

curl -X PUT -H "Authorization: secret" -d '{"name":"Jane Doe", "email":"jane@example.com", "password":"mynewpassword"}' http://localhost:8080/users/1
Enter fullscreen mode Exit fullscreen mode

Deleting a User

You can delete a user by sending a DELETE request with the user ID.

curl -X DELETE -H "Authorization: secret" http://localhost:8080/users/1
Enter fullscreen mode Exit fullscreen mode

Wrapping Up

Flight is a great choice for building simple and lightweight applications quickly. It offers the essential features needed for creating a RESTful API while being easy to learn and use. For many projects, Flight has plenty of features to help maintain the long term needs for your project. For more complex applications, you might consider using more robust frameworks like Laravel, CakePHP, or CodeIgniter, depending on your specific needs.

If you made it this far, here is the code used in this article.

Top comments (4)

Collapse
 
gbhorwood profile image
grant horwood

excellent article.

Collapse
 
n0nag0n profile image
n0nag0n

Thanks so much! I've got another one coming on how to build out a blog that really lets Flight's features shine through!

Collapse
 
pdoren profile image
Pedro Doren

Great! Do you prefer Flight over Fatfree?

Collapse
 
n0nag0n profile image
n0nag0n

Yes actually! I worked with Fat-Free for years and had a couple issues with it (not massive, but annoying to say the least). Flight solves those issues and I feel helps keep my projects a little cleaner and a little less hacky.