Welcome to a tutorial and example on how to create a simple REST API with PHP and MYSQL. The term “REST API” probably sounds intimidating to some beginners, but in actual fact, it is actually something really simple.
In simple words, a REST API is nothing but a service endpoint.
In even much simpler words, REST API is exactly like a website, but without HTML, CSS, JavaScript; It simply accepts a user request, processes it, and responds with the results.
See? Not so difficult to understand right? I don’t know why some developers fear it so much. In my opinion, it is much easier to develop a full-stack app.
If you learn from a practical example like me instead of learning from all text and theory and you are in for a treat. We will now look into a simple example in which we will create a basic login system.
Creating Users Table
Assuming that you already created a database in your PhpMyAdmin dashboard, we are going to create a table of users.
CREATE TABLE `users` (
`user_id` int(11) NOT NULL,
`user_email` varchar(255) NOT NULL,
`user_password` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `users`
ADD PRIMARY KEY (`user_id`),
ADD UNIQUE KEY `user_email` (`user_email`);
ALTER TABLE `users`
MODIFY `user_id` int(11) NOT NULL AUTO_INCREMENT;
INSERT INTO `users` (`user_id`, `user_email`, `user_password`) VALUES
(1, '[email protected]', '$2y$10$FXxqEZfiiThcCRyJbJJm8.Yktp39YlQcuntrqVABWGkQ1RJIKe5rC');
Here we are creating users table where user_id is primary key & auto increment and user_email is unique.
We are also inserting dummy entry where email is [email protected] and password is 12345.
User Class and Method
<?php
class Users {
// (A) CONSTRUCTOR - CONNECT TO DATABASE
private $pdo = null;
private $stmt = null;
public $error = "";
function __construct () {
try {
$this->pdo = new PDO(
"mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=".DB_CHARSET,
DB_USER, DB_PASSWORD, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]
);
} catch (Exception $ex) { die($ex->getMessage()); }
}
// (B) DESTRUCTOR - CLOSE DATABASE CONNECTION
function __destruct () {
if ($this->stmt!==null) { $this->stmt = null; }
if ($this->pdo!==null) { $this->pdo = null; }
}
// (C) SUPPORT FUNCTION - SQL QUERY
function query ($sql, $data) {
try {
$this->stmt = $this->pdo->prepare($sql);
$this->stmt->execute($data);
return true;
} catch (Exception $ex) {
$this->error = $ex->getMessage();
return false;
}
}
// (D) CREATE/UPDATE USER
function save ($email, $pass, $id=null) {
if ($id===null) {
return $this->query(
"INSERT INTO `users` (`user_email`, `user_password`) VALUES (?,?)",
[$email, password_hash($pass, PASSWORD_BCRYPT)]
);
} else {
return $this->query(
"UPDATE `users` SET `user_email`=?, `user_password`=? WHERE `user_id`=?",
[$email, password_hash($pass, PASSWORD_BCRYPT), $id]
);
}
}
// (E) GET USER
function get ($id) {
if ($this->query(
"SELECT * FROM `users` WHERE `user_".(is_numeric($id)?"id":"email")."`=?", [$id]
)) { return $this->stmt->fetch(); }
return false;
}
// (F) VERIFY USER (FOR LOGIN)
function verify ($email, $pass) {
// (F1) GET USER
$user = $this->get($email);
if (!is_array($user)) { return false; }
// (F2) PASSWORD CHECK
if (password_verify($pass, $user['user_password'])) {
$_SESSION['user'] = [
"id" => $user['user_id'],
"email" => $user['user_email']
];
return true;
} else { return false; }
}
// (G) DELETE USER
function del ($id) {
return $this->query(
"DELETE FROM `users` WHERE `user_id`=?", [$id]
);
}
}
// (H) DATABASE SETTINGS - CHANGE TO YOUR OWN!
define('DB_HOST', 'localhost');
define('DB_NAME', 'test');
define('DB_CHARSET', 'utf8');
define('DB_USER', 'root');
define('DB_PASSWORD', '');
// (I) START!
session_start();
$USR = new Users();
Yikes! This looks massive, but keep calm and study slowly:
- A & B – When the
$USR = new Users()
object is created, the constructor will automatically connect to the database; The destructor closes the connection when done. - C –
function query()
is nothing but a helper function to run SQL queries. - D to G – There are only 4 functions, and all of them are essentially just SQL statements!
function save()
Add a new user, or edit an existing one.function get()
Get a user by ID or email.function verify()
Verify a given email and password (for login).function del()
Delete a user.
API Endpoints
<?php
// (A) LOAD USER LIBRARY
require "2-users-lib.php";
// (B) STANDARD JSON RESPONSE
function respond ($status, $message, $more=null, $http=null) {
if ($http !== null) { http_response_code($http); }
exit(json_encode([
"status" => $status,
"message" => $message,
"more" => $more
]));
}
// (C) LOGIN CHECK
function lcheck () {
if (!isset($_SESSION['user'])) {
respond(0, "Please sign in first", null, 403);
}
}
// (D) HANDLE REQUEST
switch ($_POST['req']) {
// (D1) BAD REQUEST
default:
respond(false, "Invalid request", null, null, 400);
break;
// (D2) SAVE USER
case "save":
lcheck();
$pass = $USR->save(
$_POST['email'], $_POST['password'],
isset($_POST['id']) ? $_POST['id'] : null
);
respond($pass, $pass?"OK":$USR->error);
break;
// (D3) GET USER
case "get":
lcheck();
$user = $USR->get($_POST['id']);
respond(true, "OK", $user);
break;
// (D4) DELETE USER
case "del":
lcheck();
$pass = $USR->del($_POST['id']);
respond($pass, $pass?"OK":$USR->error);
break;
// (D5) LOGIN
case "in":
// ALREADY SIGNED IN
if (isset($_SESSION['user'])) { respond(true, "OK"); }
// CREDENTIALS CHECK
$pass = $USR->verify($_POST['email'], $_POST['password']);
respond($pass, $pass?"OK":"Invalid email/password");
break;
// (D6) LOGOUT
case "out":
unset($_SESSION['user']);
respond(true, "OK");
break;
}
Don’t be intimidated by the “confusing” code again, how this API endpoint work should be self-explanatory.
- Send a
$_POST['req']
to specify the request, followed by the required parameters. - For example – To add a new user, we send
$_POST['req'] = "save"
,$_POST['email'] = "[email protected]"
, and$_POST['password'] = "SECRET"
to this endpoint. - The API will respond in a JSON encoded format – A
status
flag on the processing, and systemmessage
.
Start the engine and test the API
<!-- (A) LOGIN -->
<form method="post" action="3-users-api.php">
<input type="text" name="req" value="in" readonly />
<input type="email" name="email" value="[email protected]" required />
<input type="text" name="password" value="123456" required />
<input type="submit" value="1 - Login"/>
</form>
Actually, that’s all for the “complicated REST API”. But go ahead – POST a login request, add a new user, update a new user. See for yourself how the API endpoint works. If you want to read more visit Borrowed Code.