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
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
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();
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',
];
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();
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);
}
}
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...
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
This will create a new user and return the user ID.
Getting All Users
curl -H "Authorization: secret" http://localhost:8080/users
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
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
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
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)
excellent article.
Thanks so much! I've got another one coming on how to build out a blog that really lets Flight's features shine through!
Great! Do you prefer Flight over Fatfree?
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.