Home PHP

How To Create A Simple REST API in PHP? Step By Step Guide!


Previously, we learned how to create, read, update and delete database records (CRUD operations) with our PHP, MySQL & OOP CRUD Tutorial.

Today, before we go to JavaScript programming, we will learn how to create a simple REST API in PHP. Enjoy our step-by-step tutorial below!

This post covers the following topics:

1.0 Project Overview
1.1 What is REST API?
1.2 Why do we need REST API?
1.3 Where REST API is used?
1.4 REST API in our tutorials

2.0 File Structure

3.0 Setup the Database
3.1 Create Categories Table
3.2 Dump Data For Categories Table
3.3 Products Table
3.4 Dump Data For Products Table
3.5 Connect to database

4.0 Read Products
4.1 Product Object
4.2 Create “read.php” file
4.3 Add Product “read()” method
4.4 Output

5.0 Create Product
5.1 Create create.php file
5.2 Product create() method

6.0 Read One Product
6.1 Create read_one.php file
6.2 Product readOne() method
6.3 Output

7.0 Update product
7.1 Create “update.php” file
7.2 Product update() method

8.0 Delete Product
8.1 Create “delete.php” file
8.2 Product delete() method

9.0 Search Products
9.1 Create “search.php” file
9.2 Create “search()” method
9.3 Output

10.0 Paginate Products
10.1 Create “read_paging.php” file
10.2 Create “core.php” file
10.3 Create “readPaging()” method
10.4 Create “count()” method
10.5 Get “paging” array
10.6 Output

11.0 Read Categories
11.1 Category object
11.2 Create “read.php” file
11.3 Category “read()” method
11.4 Output

12.0 Download Source Codes
13.0 What’s Next?
14.0 Related Tutorials
15.0 Notes

Before we start, we want to let you know that your feedback is important to us!

If there's a section in this tutorial that is confusing or hard to understand, we consider it as a problem. Please let us know. We will solve this problem within 24 hours.

Send a detailed description of the problem to my email to mike@codeofaninja.com today. Use "codeofaninja.com improvement" as the subject of your email. Thank you!

1.0 Project Overview

1.1 What is REST API?

To define “REST API”, we have to know what is “REST” and what is “API” first. I’ll do my best to explain it in simple terms because REST has a lot of concepts inside of it that could mean a lot of things.

REST stands for “REpresentational State Transfer”. It is a concept or architecture for managing information over the internet. REST concepts are referred to as resources. A representation of a resource must be stateless. It is usually represented by JSON. This post is worth reading: How I Explained REST to My Wife?

API stands for “Application Programming Interface”. It is a set or rules that allows one piece of software application to talk to another. Those “rules” can include create, read, update and delete operations. If you want to learn more, watch the video below.

REST API enable your application to cooperate with one or several different applications using REST concepts. If you want to learn more, watch the video below.

1.2 Why do we need REST API?

In many applications, REST API is a need because this is the lightest way to create, read, update or delete information between different applications over the internet or HTTP protocol. This information is presented to the user in an instant especially if you use JavaScript to render the data on a webpage.

1.3 Where REST API is used?

REST API can be used by any application that can connect to the internet. If data from an application can be created, read, updated or deleted using another application, it usually means a REST API is used.

1.4 REST API in our tutorials

A REST API is needed for our JavaScript programming tutorials. This post will help you a lot with that need. Our JavaScript programming tutorials includes the following topics:

But don’t mind those topics for now. We will do it one step at a time. You don’t need to learn all of it as well. Just choose what you need to learn.

Also, please note that this PHP REST API is not yet in its final form. We still have some work to do with .htaccess for better URLs and more.

But one thing is for sure, this source codes is good enough and works for our JavaScript tutorials.

2.0 File Structure

At the end of this tutorial, we will have the following folders and files.
├─ api/
├─── config/
├────── core.php – file used for core configuration
├────── database.php – file used for connecting to the database.
├─── objects/
├────── product.php – contains properties and methods for “product” database queries.
├────── category.php – contains properties and methods for “category” database queries.
├─── product/
├────── create.php – file that will accept posted product data to be saved to database.
├────── delete.php – file that will accept a product ID to delete a database record.
├────── read.php – file that will output JSON data based from “products” database records.
├────── read_paging.php – file that will output “products” JSON data with pagination.
├────── read_one.php – file that will accept product ID to read a record from the database.
├────── update.php – file that will accept a product ID to update a database record.
├────── search.php – file that will accept keywords parameter to search “products” database.
├─── category/
├────── read.php – file that will output JSON data based from “categories” database records.
├─── shared/
├────── utilities.php – file that will return pagination array.

3.0 Setup the Database

Using PhpMyAdmin, create a new “api_db” database. Yes, “api_db” is the database name. After that, run the following SQL queries to create new tables with sample data.

3.1 Create Categories Table

CREATE TABLE IF NOT EXISTS `categories` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(256) NOT NULL,
  `description` text NOT NULL,
  `created` datetime NOT NULL,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=19 ;

3.2 Dump Data For Categories Table

INSERT INTO `categories` (`id`, `name`, `description`, `created`, `modified`) VALUES
(1, 'Fashion', 'Category for anything related to fashion.', '2014-06-01 00:35:07', '2014-05-30 17:34:33'),
(2, 'Electronics', 'Gadgets, drones and more.', '2014-06-01 00:35:07', '2014-05-30 17:34:33'),
(3, 'Motors', 'Motor sports and more', '2014-06-01 00:35:07', '2014-05-30 17:34:54'),
(5, 'Movies', 'Movie products.', '0000-00-00 00:00:00', '2016-01-08 13:27:26'),
(6, 'Books', 'Kindle books, audio books and more.', '0000-00-00 00:00:00', '2016-01-08 13:27:47'),
(13, 'Sports', 'Drop into new winter gear.', '2016-01-09 02:24:24', '2016-01-09 01:24:24');

3.3 Products Table

CREATE TABLE IF NOT EXISTS `products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL,
  `description` text NOT NULL,
  `price` decimal(10,0) NOT NULL,
  `category_id` int(11) NOT NULL,
  `created` datetime NOT NULL,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=65 ;

3.4 Dump Data For Products Table

INSERT INTO `products` (`id`, `name`, `description`, `price`, `category_id`, `created`, `modified`) VALUES
(1, 'LG P880 4X HD', 'My first awesome phone!', '336', 3, '2014-06-01 01:12:26', '2014-05-31 17:12:26'),
(2, 'Google Nexus 4', 'The most awesome phone of 2013!', '299', 2, '2014-06-01 01:12:26', '2014-05-31 17:12:26'),
(3, 'Samsung Galaxy S4', 'How about no?', '600', 3, '2014-06-01 01:12:26', '2014-05-31 17:12:26'),
(6, 'Bench Shirt', 'The best shirt!', '29', 1, '2014-06-01 01:12:26', '2014-05-31 02:12:21'),
(7, 'Lenovo Laptop', 'My business partner.', '399', 2, '2014-06-01 01:13:45', '2014-05-31 02:13:39'),
(8, 'Samsung Galaxy Tab 10.1', 'Good tablet.', '259', 2, '2014-06-01 01:14:13', '2014-05-31 02:14:08'),
(9, 'Spalding Watch', 'My sports watch.', '199', 1, '2014-06-01 01:18:36', '2014-05-31 02:18:31'),
(10, 'Sony Smart Watch', 'The coolest smart watch!', '300', 2, '2014-06-06 17:10:01', '2014-06-05 18:09:51'),
(11, 'Huawei Y300', 'For testing purposes.', '100', 2, '2014-06-06 17:11:04', '2014-06-05 18:10:54'),
(12, 'Abercrombie Lake Arnold Shirt', 'Perfect as gift!', '60', 1, '2014-06-06 17:12:21', '2014-06-05 18:12:11'),
(13, 'Abercrombie Allen Brook Shirt', 'Cool red shirt!', '70', 1, '2014-06-06 17:12:59', '2014-06-05 18:12:49'),
(26, 'Another product', 'Awesome product!', '555', 2, '2014-11-22 19:07:34', '2014-11-21 20:07:34'),
(28, 'Wallet', 'You can absolutely use this one!', '799', 6, '2014-12-04 21:12:03', '2014-12-03 22:12:03'),
(31, 'Amanda Waller Shirt', 'New awesome shirt!', '333', 1, '2014-12-13 00:52:54', '2014-12-12 01:52:54'),
(42, 'Nike Shoes for Men', 'Nike Shoes', '12999', 3, '2015-12-12 06:47:08', '2015-12-12 05:47:08'),
(48, 'Bristol Shoes', 'Awesome shoes.', '999', 5, '2016-01-08 06:36:37', '2016-01-08 05:36:37'),
(60, 'Rolex Watch', 'Luxury watch.', '25000', 1, '2016-01-11 15:46:02', '2016-01-11 14:46:02');

3.5 Connect to database

Create “config” folder. Open that folder and create “database.php” file. Put the following code inside it.

<?php
class Database{

	// specify your own database credentials
	private $host = "localhost";
	private $db_name = "api_db";
	private $username = "root";
	private $password = "";
	public $conn;

	// get the database connection
	public function getConnection(){

		$this->conn = null;

		try{
			$this->conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->db_name, $this->username, $this->password);
			$this->conn->exec("set names utf8");
		}catch(PDOException $exception){
			echo "Connection error: " . $exception->getMessage();
		}

		return $this->conn;
	}
}
?>

4.0 Read Products

4.1 Product Object

Create “objects” folder. Open that folder and create “product.php” file. Put the following code inside it.

<?php
class Product{

	// database connection and table name
	private $conn;
	private $table_name = "products";

	// object properties
	public $id;
	public $name;
	public $description;
	public $price;
	public $category_id;
	public $category_name;
	public $created;

	// constructor with $db as database connection
	public function __construct($db){
		$this->conn = $db;
	}
}

4.2 Create “read.php” file

Create “product” folder. Open that folder and create “read.php” file. Put the following code inside it.

<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");

// include database and object files
include_once '../config/database.php';
include_once '../objects/product.php';

// instantiate database and product object
$database = new Database();
$db = $database->getConnection();

// initialize object
$product = new Product($db);

// query products
$stmt = $product->read();
$num = $stmt->rowCount();

// check if more than 0 record found
if($num>0){

	// products array
	$products_arr=array();
	$products_arr["records"]=array();

	// retrieve our table contents
	// fetch() is faster than fetchAll()
	// http://stackoverflow.com/questions/2770630/pdofetchall-vs-pdofetch-in-a-loop
	while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
		// extract row
		// this will make $row['name'] to
		// just $name only
		extract($row);

		$product_item=array(
			"id" => $id,
			"name" => $name,
			"description" => html_entity_decode($description),
			"price" => $price,
			"category_id" => $category_id,
			"category_name" => $category_name
		);

		array_push($products_arr["records"], $product_item);
	}

	echo json_encode($products_arr);
}

else{
    echo json_encode(
		array("message" => "No products found.")
	);
}
?>

4.3 Add Product “read()” method

Open “objects” folder. Open “product.php” file. The code on the previous section will not work without the following code in “product.php” file. Add the following method inside the “Product” class.

// read products
function read(){

	// select all query
	$query = "SELECT
				c.name as category_name, p.id, p.name, p.description, p.price, p.category_id, p.created
			FROM
				" . $this->table_name . " p
				LEFT JOIN
					categories c
						ON p.category_id = c.id
			ORDER BY
				p.created DESC";

	// prepare query statement
	$stmt = $this->conn->prepare($query);

	// execute query
	$stmt->execute();

	return $stmt;
}

4.4 Output

If you develop on localhost and will run the read.php file using this URL: http://localhost/api/product/read.php

You will see an output like this:

By the way, I’m using a Chrome extension called JSONView to make the JSON data readable in the browser.

5.0 Create Product

5.1 Create create.php file

Open “product” folder. Create a new “create.php” file. Open that file and put the following code inside it.

<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");

// get database connection
include_once '../config/database.php';

// instantiate product object
include_once '../objects/product.php';

$database = new Database();
$db = $database->getConnection();

$product = new Product($db);

// get posted data
$data = json_decode(file_get_contents("php://input"));

// set product property values
$product->name = $data->name;
$product->price = $data->price;
$product->description = $data->description;
$product->category_id = $data->category_id;
$product->created = date('Y-m-d H:i:s');

// create the product
if($product->create()){
	echo '{';
		echo '"message": "Product was created."';
	echo '}';
}

// if unable to create the product, tell the user
else{
	echo '{';
		echo '"message": "Unable to create product."';
	echo '}';
}
?>

5.2 Product create() method

Open “objects” folder. Open “product.php” file. The previous section will not work without the following code inside that “product.php” file.

// create product
function create(){

	// query to insert record
	$query = "INSERT INTO
				" . $this->table_name . "
			SET
				name=:name, price=:price, description=:description, category_id=:category_id, created=:created";

	// prepare query
	$stmt = $this->conn->prepare($query);

	// sanitize
	$this->name=htmlspecialchars(strip_tags($this->name));
	$this->price=htmlspecialchars(strip_tags($this->price));
	$this->description=htmlspecialchars(strip_tags($this->description));
	$this->category_id=htmlspecialchars(strip_tags($this->category_id));
	$this->created=htmlspecialchars(strip_tags($this->created));

	// bind values
	$stmt->bindParam(":name", $this->name);
	$stmt->bindParam(":price", $this->price);
	$stmt->bindParam(":description", $this->description);
	$stmt->bindParam(":category_id", $this->category_id);
	$stmt->bindParam(":created", $this->created);

	// execute query
	if($stmt->execute()){
		return true;
	}else{
		return false;
	}
}

I highly recommend completing this whole tutorial first. But if you want to test the code above, you have to use our JavaScript code. The reason is our JavaScript code is designed to work with this REST API.

Please complete one of our JavaScript programming tutorials. This same concept applies to our “update” and “delete” code.

6.0 Read One Product

6.1 Create read_one.php file

Open “product” folder. Create new “read_one.php” file. Open that file and put the following code.

<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: access");
header("Access-Control-Allow-Methods: GET");
header("Access-Control-Allow-Credentials: true");
header('Content-Type: application/json');

// include database and object files
include_once '../config/database.php';
include_once '../objects/product.php';

// get database connection
$database = new Database();
$db = $database->getConnection();

// prepare product object
$product = new Product($db);

// set ID property of product to be edited
$product->id = isset($_GET['id']) ? $_GET['id'] : die();

// read the details of product to be edited
$product->readOne();

// create array
$product_arr = array(
	"id" =>  $product->id,
	"name" => $product->name,
	"description" => $product->description,
	"price" => $product->price,
	"category_id" => $product->category_id,
	"category_name" => $product->category_name

);

// make it json format
print_r(json_encode($product_arr));
?>

6.2 Product readOne() method

Open “objects” folder. Open “product.php” file. The previous section will the work without the following code inside the Product class.

// used when filling up the update product form
function readOne(){

	// query to read single record
	$query = "SELECT
				c.name as category_name, p.id, p.name, p.description, p.price, p.category_id, p.created
			FROM
				" . $this->table_name . " p
				LEFT JOIN
					categories c
						ON p.category_id = c.id
			WHERE
				p.id = ?
			LIMIT
				0,1";

	// prepare query statement
	$stmt = $this->conn->prepare( $query );

	// bind id of product to be updated
	$stmt->bindParam(1, $this->id);

	// execute query
	$stmt->execute();

	// get retrieved row
	$row = $stmt->fetch(PDO::FETCH_ASSOC);

	// set values to object properties
	$this->name = $row['name'];
	$this->price = $row['price'];
	$this->description = $row['description'];
	$this->category_id = $row['category_id'];
	$this->category_name = $row['category_name'];
}

6.3 Output

If you develop on localhost and will run the read_one.php file using this URL: http://localhost/api/product/read_one.php?id=60

As you can see in the URL above, an ID parameter value (id=60) has to be passed.

You will see an output like this:

7.0 Update product

7.1 Create “update.php” file

Open “product” folder. Create new “update.php” file. Open that file and put the following code inside it.

<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");

// include database and object files
include_once '../config/database.php';
include_once '../objects/product.php';

// get database connection
$database = new Database();
$db = $database->getConnection();

// prepare product object
$product = new Product($db);

// get id of product to be edited
$data = json_decode(file_get_contents("php://input"));

// set ID property of product to be edited
$product->id = $data->id;

// set product property values
$product->name = $data->name;
$product->price = $data->price;
$product->description = $data->description;
$product->category_id = $data->category_id;

// update the product
if($product->update()){
	echo '{';
		echo '"message": "Product was updated."';
	echo '}';
}

// if unable to update the product, tell the user
else{
	echo '{';
		echo '"message": "Unable to update product."';
	echo '}';
}
?>

7.2 Product update() method

Open “objects” folder. Open “product.php” file. The previous section will the work without the following code inside the Product class.

// update the product
function update(){

	// update query
	$query = "UPDATE
				" . $this->table_name . "
			SET
				name = :name,
				price = :price,
				description = :description,
				category_id = :category_id
			WHERE
				id = :id";

	// prepare query statement
	$stmt = $this->conn->prepare($query);

	// sanitize
	$this->name=htmlspecialchars(strip_tags($this->name));
	$this->price=htmlspecialchars(strip_tags($this->price));
	$this->description=htmlspecialchars(strip_tags($this->description));
	$this->category_id=htmlspecialchars(strip_tags($this->category_id));
	$this->id=htmlspecialchars(strip_tags($this->id));

	// bind new values
	$stmt->bindParam(':name', $this->name);
	$stmt->bindParam(':price', $this->price);
	$stmt->bindParam(':description', $this->description);
	$stmt->bindParam(':category_id', $this->category_id);
	$stmt->bindParam(':id', $this->id);

	// execute the query
	if($stmt->execute()){
		return true;
	}else{
		return false;
	}
}

8.0 Delete Product

8.1 Create “delete.php” file

Open “product” folder. Create new “delete.php” file. Open that file and put the following code inside it.

<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");


// include database and object file
include_once '../config/database.php';
include_once '../objects/product.php';

// get database connection
$database = new Database();
$db = $database->getConnection();

// prepare product object
$product = new Product($db);

// get product id
$data = json_decode(file_get_contents("php://input"));

// set product id to be deleted
$product->id = $data->id;

// delete the product
if($product->delete()){
	echo '{';
		echo '"message": "Product was deleted."';
	echo '}';
}

// if unable to delete the product
else{
	echo '{';
		echo '"message": "Unable to delete object."';
	echo '}';
}
?>

8.2 Product delete() method

Open “objects” folder. Open “product.php” file. The previous section will the work without the following code inside the Product class.

// delete the product
function delete(){

	// delete query
	$query = "DELETE FROM " . $this->table_name . " WHERE id = ?";

	// prepare query
	$stmt = $this->conn->prepare($query);

	// sanitize
	$this->id=htmlspecialchars(strip_tags($this->id));

	// bind id of record to delete
	$stmt->bindParam(1, $this->id);

	// execute query
	if($stmt->execute()){
		return true;
	}

	return false;
	
}

9.0 Search Products

9.1 Create “search.php” file

Open “product” folder. Create “search.php” file. Open that file and put the following code.

<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");

// include database and object files
include_once '../config/database.php';
include_once '../objects/product.php';

// instantiate database and product object
$database = new Database();
$db = $database->getConnection();

// initialize object
$product = new Product($db);

// get keywords
$keywords=isset($_GET["s"]) ? $_GET["s"] : "";

// query products
$stmt = $product->search($keywords);
$num = $stmt->rowCount();

// check if more than 0 record found
if($num>0){

	// products array
	$products_arr=array();
	$products_arr["records"]=array();

	// retrieve our table contents
	// fetch() is faster than fetchAll()
	// http://stackoverflow.com/questions/2770630/pdofetchall-vs-pdofetch-in-a-loop
	while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
		// extract row
		// this will make $row['name'] to
		// just $name only
		extract($row);

		$product_item=array(
			"id" => $id,
			"name" => $name,
			"description" => html_entity_decode($description),
			"price" => $price,
			"category_id" => $category_id,
			"category_name" => $category_name
		);

		array_push($products_arr["records"], $product_item);
	}

	echo json_encode($products_arr);
}

else{
    echo json_encode(
		array("message" => "No products found.")
	);
}
?>

9.2 Create search() method

Open “objects” folder. Open “product.php” file. Add the following search() method.

// search products
function search($keywords){

	// select all query
	$query = "SELECT
				c.name as category_name, p.id, p.name, p.description, p.price, p.category_id, p.created
			FROM
				" . $this->table_name . " p
				LEFT JOIN
					categories c
						ON p.category_id = c.id
			WHERE
				p.name LIKE ? OR p.description LIKE ? OR c.name LIKE ?
			ORDER BY
				p.created DESC";

	// prepare query statement
	$stmt = $this->conn->prepare($query);

	// sanitize
	$keywords=htmlspecialchars(strip_tags($keywords));
	$keywords = "%{$keywords}%";

	// bind
	$stmt->bindParam(1, $keywords);
	$stmt->bindParam(2, $keywords);
	$stmt->bindParam(3, $keywords);

	// execute query
	$stmt->execute();

	return $stmt;
}

9.3 Output

Output should look like the following. Notice the sample search keyword on the URL.

Try this link: http://localhost/api/product/search.php?s=shirt

10.0 Paginate Products

10.1 Create “read_paging.php” file

On the /api/product/ folder, create “read_paging.php” file.

<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");

// include database and object files
include_once '../config/core.php';
include_once '../shared/utilities.php';
include_once '../config/database.php';
include_once '../objects/product.php';

// utilities
$utilities = new Utilities();

// instantiate database and product object
$database = new Database();
$db = $database->getConnection();

// initialize object
$product = new Product($db);

// query products
$stmt = $product->readPaging($from_record_num, $records_per_page);
$num = $stmt->rowCount();

// check if more than 0 record found
if($num>0){

	// products array
	$products_arr=array();
	$products_arr["records"]=array();
	$products_arr["paging"]=array();

	// retrieve our table contents
	// fetch() is faster than fetchAll()
	// http://stackoverflow.com/questions/2770630/pdofetchall-vs-pdofetch-in-a-loop
	while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
		// extract row
		// this will make $row['name'] to
		// just $name only
		extract($row);

		$product_item=array(
			"id" => $id,
			"name" => $name,
			"description" => html_entity_decode($description),
			"price" => $price,
			"category_id" => $category_id,
			"category_name" => $category_name
		);

		array_push($products_arr["records"], $product_item);
	}


	// include paging
	$total_rows=$product->count();
	$page_url="{$home_url}product/read_paging.php?";
	$paging=$utilities->getPaging($page, $total_rows, $records_per_page, $page_url);
	$products_arr["paging"]=$paging;

	echo json_encode($products_arr);
}

else{
    echo json_encode(
		array("message" => "No products found.")
	);
}
?>

10.2 Create “core.php” file

This file holds our core configuration like the home URL and pagination variables.

Open the “config” folder and create “core.php” file. Open “core.php” file and place the following code.

<?php
// show error reporting
ini_set('display_errors', 1);
error_reporting(E_ALL);

// home page url
$home_url="http://localhost/api/";

// page given in URL parameter, default page is one
$page = isset($_GET['page']) ? $_GET['page'] : 1;

// set number of records per page
$records_per_page = 5;

// calculate for the query LIMIT clause
$from_record_num = ($records_per_page * $page) - $records_per_page;
?>

10.3 Create “readPaging()” method

Open product.php file in /api/objects/ folder. Add the following method inside product class. This method will return a list of records limited to what we set in “$records_per_page” of the previous section.

// read products with pagination
public function readPaging($from_record_num, $records_per_page){

	// select query
	$query = "SELECT
				c.name as category_name, p.id, p.name, p.description, p.price, p.category_id, p.created
			FROM
				" . $this->table_name . " p
				LEFT JOIN
					categories c
						ON p.category_id = c.id
			ORDER BY p.created DESC
			LIMIT ?, ?";

	// prepare query statement
	$stmt = $this->conn->prepare( $query );

	// bind variable values
	$stmt->bindParam(1, $from_record_num, PDO::PARAM_INT);
	$stmt->bindParam(2, $records_per_page, PDO::PARAM_INT);

	// execute query
	$stmt->execute();

	// return values from database
	return $stmt;
}

10.4 Create “count()” method

Still in the product class (product.php file), add the following method. The total rows are needed to build the pagination array. It is included in the ‘paging’ computation.

// used for paging products
public function count(){
	$query = "SELECT COUNT(*) as total_rows FROM " . $this->table_name . "";

	$stmt = $this->conn->prepare( $query );
	$stmt->execute();
	$row = $stmt->fetch(PDO::FETCH_ASSOC);

	return $row['total_rows'];
}

10.5 Get “paging” array

Create “shared” folder.
Open “shared” folder and create “utilities.php” file.
Open “utilities.php” file and put the following code.

<?php
class Utilities{

    public function getPaging($page, $total_rows, $records_per_page, $page_url){

        // paging array
        $paging_arr=array();

        // button for first page
        $paging_arr["first"] = $page>1 ? "{$page_url}page=1" : "";

        // count all products in the database to calculate total pages
        $total_pages = ceil($total_rows / $records_per_page);

        // range of links to show
        $range = 2;

        // display links to 'range of pages' around 'current page'
        $initial_num = $page - $range;
        $condition_limit_num = ($page + $range)  + 1;

        $paging_arr['pages']=array();
        $page_count=0;
        
        for($x=$initial_num; $x<$condition_limit_num; $x++){
            // be sure '$x is greater than 0' AND 'less than or equal to the $total_pages'
            if(($x > 0) && ($x <= $total_pages)){
                $paging_arr['pages'][$page_count]["page"]=$x;
                $paging_arr['pages'][$page_count]["url"]="{$page_url}page={$x}";
                $paging_arr['pages'][$page_count]["current_page"] = $x==$page ? "yes" : "no";

                $page_count++;
            }
        }

        // button for last page
        $paging_arr["last"] = $page<$total_pages ? "{$page_url}page={$total_pages}" : "";

        // json format
        return $paging_arr;
    }

}
?>

10.6 Output

You should see “paging” in the JSON output.

11.0 Read Categories

11.1 Create “category.php” file

Open “objects” folder. Create new “category.php” file. Put the following code inside the “category.php” file.

<?php
class Category{

	// database connection and table name
	private $conn;
	private $table_name = "categories";

	// object properties
	public $id;
	public $name;
	public $description;
	public $created;

	public function __construct($db){
		$this->conn = $db;
	}

	// used by select drop-down list
	public function readAll(){
		//select all data
		$query = "SELECT
					id, name, description
				FROM
					" . $this->table_name . "
				ORDER BY
					name";

		$stmt = $this->conn->prepare( $query );
		$stmt->execute();

		return $stmt;
	}
}
?>

11.2 Create “read.php” file

Create new “category” folder. Open that folder and create new “read.php” file inside it. Open “read.php” file and put the following code.

<?php
// required header
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");

// include database and object files
include_once '../config/database.php';
include_once '../objects/category.php';

// instantiate database and category object
$database = new Database();
$db = $database->getConnection();

// initialize object
$category = new Category($db);

// query categorys
$stmt = $category->read();
$num = $stmt->rowCount();

// check if more than 0 record found
if($num>0){

	// products array
	$categories_arr=array();
	$categories_arr["records"]=array();

	// retrieve our table contents
	// fetch() is faster than fetchAll()
	// http://stackoverflow.com/questions/2770630/pdofetchall-vs-pdofetch-in-a-loop
	while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
		// extract row
		// this will make $row['name'] to
		// just $name only
		extract($row);

		$category_item=array(
			"id" => $id,
			"name" => $name,
			"description" => html_entity_decode($description)
		);

		array_push($categories_arr["records"], $category_item);
	}

	echo json_encode($categories_arr);
}

else{
    echo json_encode(
		array("message" => "No products found.")
	);
}
?>

11.3 Add Category “read()” method

Open “objects” folder. Open “category.php” file. The previous section’s code will not work without the following code inside the “category.php” file. Add the following method inside the “Category” class.

<?php
// used by select drop-down list
public function read(){

	//select all data
	$query = "SELECT
				id, name, description
			FROM
				" . $this->table_name . "
			ORDER BY
				name";

	$stmt = $this->conn->prepare( $query );
	$stmt->execute();

	return $stmt;
}

?>

11.4 Output

If you develop on localhost and will run the read.php file using this URL: http://localhost/api/category/read.php

You will see an output like this:

12.0 Download Source Codes

IF you download any source codes from our AJAX Tutorial, React Tutorial, AngularJS Tutorial or Angular 2 Tutorial , this PHP REST API source code is free and included in their respective packages.

BUT if you need to download this PHP REST API source code only, you can do it using the green download button below.

FEATURES PHP REST API
Create product YES
Read products YES
Read one product YES
Update product YES
Delete product YES
Search products YES
Read & search products with pagination YES
Create category YES
Read categories YES
Read one category YES
Update category YES
Delete category YES
Search categories YES
Read and search categories with pagination YES
FREE email support for 3 months YES
Source code updates via email YES

13.0 What’s Next?

Next, we will learn how to create, read, update and delete database records with our jQuery AJAX CRUD Tutorial.

14.0 Related Tutorials

15.0 Notes

#1 Found An Issue?

If you found a problem with this code, we can solve it faster via Email or FB message, please send me a message via email mike@codeofaninja.com, or via our official Facebook page!

Please be more detailed about your issue. Best if you can provide an error message and your test or page URL. Thanks!

Please feel free to comment if you have any questions, suggestions, found something wrong or want to contribute to this code.

#2 Become a true Ninja!

We constantly add new tutorials and improve our existing tutorials and source codes. Be one of the first to know an update by subscribing to our FREE newsletter. Get a FREE EBOOK as well. CLICK HERE TO SUBSCRIBE FOR FREE!

#3 Thank You!

Please note that this post is not yet in its final form. We are going to update this post so it will be perfect in the future.

If you have a friend or know someone who needs this PHP REST API Tutorial, please share this page to them! I know you will help them a lot by doing it. Thanks!