在本教程中,我将教你如何用PHP和MySQL构建一个简单的REST API。
当涉及到通过API暴露数据和构建Web服务时,REST已经成为事实上的标准。事实上,现在大多数Web应用程序都是通过REST API来访问和暴露数据的。随着能够毫不费力地消费REST API的前端框架的普及,如果你的网络应用能够暴露REST API,这对你来说永远是一个加分项。
在这篇文章中,我们将建立一个简单的演示应用程序,它允许你通过REST端点从MySQL数据库中获取一个用户列表。
设置骨架
在这一节中,我们将简单介绍一下项目结构。
让我们看一下下面的结构。
├── Controller
│ └── Api
│ ├── BaseController.php
│ └── UserController.php
├── inc
│ ├── bootstrap.php
│ └── config.php
├── index.php
└── Model
├── Database.php
└── UserModel.php
让我们试着理解项目的结构。
- index.php:是我们应用程序的入口。它将充当我们应用程序的前台控制器。
- inc/config.php: 保存我们应用程序的配置信息。主要是,它将持有数据库的证书。
- inc/bootstrap.php: 用来启动我们的应用程序,包括必要的文件。
- Model/Database.php:数据库访问层,将用于与底层的MySQL数据库交互。
- Model/UserModel.php:
User模型文件,实现必要的方法与MySQL数据库中的用户表交互。 - Controller/Api/BaseController.php: 一个基本的控制器文件,它拥有常用的实用方法。
- Controller/Api/UserController.php:
User控制器文件,它拥有必要的应用程序代码来处理REST API调用。
这就是我们在接下来的文章中要实现的基本设置。
创建一个数据库和模型类
在这一部分,我们将创建一个数据库和用户表。我们还将创建必要的模型类,用于从数据库中获取用户。
创建一个数据库和用户表
通过在你的MySQL终端执行以下命令来创建rest_api_demo 数据库。(在命令行中用命令mysql )。
$CREATE DATABASE rest_api_demo;
如果你喜欢用这种方式处理你的数据库,你也可以使用像phpMyAdmin这样的工具。
一旦创建了rest_api_demo 数据库,继续通过运行以下语句创建users 表。
$use rest_api_demo;
$CREATE TABLE `users` (
`user_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`user_email` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`user_status` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
这将在rest_api_demo 数据库中创建users 表。你还想用一些假的记录来填充这个表,以达到测试的目的。插入几条记录,你就可以开始了
创建模型类
在这一部分,我们将创建必要的模型类。
创建Model/Database.php文件,内容如下。
<?php
class Database
{
protected $connection = null;
public function __construct()
{
try {
$this->connection = new mysqli(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_DATABASE_NAME);
if ( mysqli_connect_errno()) {
throw new Exception("Could not connect to database.");
}
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
}
public function select($query = "" , $params = [])
{
try {
$stmt = $this->executeStatement( $query , $params );
$result = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
$stmt->close();
return $result;
} catch(Exception $e) {
throw New Exception( $e->getMessage() );
}
return false;
}
private function executeStatement($query = "" , $params = [])
{
try {
$stmt = $this->connection->prepare( $query );
if($stmt === false) {
throw New Exception("Unable to do prepared statement: " . $query);
}
if( $params ) {
$stmt->bind_param($params[0], $params[1]);
}
$stmt->execute();
return $stmt;
} catch(Exception $e) {
throw New Exception( $e->getMessage() );
}
}
}
这是一个数据库访问层类,它允许我们建立一个与MySQL数据库的连接。除了建立连接外,它还包含通用方法,如select 和executeStatement ,允许我们从数据库中选择记录。我们不会直接使用Database 类,我们将创建相应的模型类,扩展Database 类,以便访问底层的MySQL数据库。
接下来,让我们创建Model/UserModel.php类,内容如下。
<?php
require_once PROJECT_ROOT_PATH . "/Model/Database.php";
class UserModel extends Database
{
public function getUsers($limit)
{
return $this->select("SELECT * FROM users ORDER BY user_id ASC LIMIT ?", ["i", $limit]);
}
}
值得注意的是,UserModel 类扩展了Database 类。
除此以外,它还包含getUsers 方法,它允许我们从MySQL数据库中选择用户。必须传递$limit 参数,这确保它不会一次选择所有记录。
当然,你可以根据你的要求在UserModel 类中定义更多的方法。在本教程中,我们将保持事情的简单性。
所以现在我们有了我们的数据库和模型类的设置。在下一节,我们将看到如何在我们的演示程序中创建控制器和相关文件。
创建应用层组件
在这一节中,我们将创建其余的文件,这些文件是我们的演示程序实际工作所需要的。
inc目录
对于初学者,我们将创建必要的配置文件。
创建inc/config.php文件,内容如下。
<?php
define("DB_HOST", "localhost");
define("DB_USERNAME", "demo");
define("DB_PASSWORD", "demo");
define("DB_DATABASE_NAME", "rest_api_demo");
请确保将所有的值更新为你在安装中使用的实际值。
接下来,继续创建inc/bootstrap.php文件,内容如下。
<?php
define("PROJECT_ROOT_PATH", __DIR__ . "/../");
// include main configuration file
require_once PROJECT_ROOT_PATH . "/inc/config.php";
// include the base controller file
require_once PROJECT_ROOT_PATH . "/Controller/Api/BaseController.php";
// include the use model file
require_once PROJECT_ROOT_PATH . "/Model/UserModel.php";
?>
首先,我们用我们应用程序的根目录初始化了PROJECT_ROOT_PATH 常数。这样,我们就可以使用PROJECT_ROOT_PATH 常数来准备我们应用程序中的绝对路径。接下来,我们包含了config.php文件,它保存了数据库连接信息。最后,我们包含了控制器和模型文件。
这就是在我们的应用程序中设置常用文件的情况。
控制器目录
在这一节中,我们将实现控制器,保存大部分的应用逻辑。
BaseController.php文件
创建Controller/Api/BaseController.php文件,内容如下。BaseController 类包含了其他控制器所使用的实用方法。
<?php
class BaseController
{
/**
* __call magic method.
*/
public function __call($name, $arguments)
{
$this->sendOutput('', array('HTTP/1.1 404 Not Found'));
}
/**
* Get URI elements.
*
* @return array
*/
protected function getUriSegments()
{
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$uri = explode( '/', $uri );
return $uri;
}
/**
* Get querystring params.
*
* @return array
*/
protected function getQueryStringParams()
{
return parse_str($_SERVER['QUERY_STRING'], $query);
}
/**
* Send API output.
*
* @param mixed $data
* @param string $httpHeader
*/
protected function sendOutput($data, $httpHeaders=array())
{
header_remove('Set-Cookie');
if (is_array($httpHeaders) && count($httpHeaders)) {
foreach ($httpHeaders as $httpHeader) {
header($httpHeader);
}
}
echo $data;
exit;
}
}
让我们快速浏览一下BaseController 类的所有方法。
__call 方法是一个神奇的方法,当你试图调用一个不存在的方法时,它会被调用。当有人试图调用一个我们没有实现的方法时,我们要利用这个机会抛出HTTP/1.1 404 Not Found 错误。如果这听起来让你感到困惑,不要担心,当我们在下一节测试我们的应用程序时,它将变得更有意义。
接下来,是getUriSegments 方法,它返回一个URI段的数组。当我们试图验证用户调用的REST端点时,它很有用。接着,是getQueryStringParams 方法,它返回一个查询字符串变量数组,这些变量与传入的请求一起被传递。
最后,是sendOutput 方法,用于发送API响应。当我们想发送API响应给用户时,我们将调用这个方法。
UserController.php文件
接下来,创建Controller/Api/UserController.php文件,内容如下。
<?php
class UserController extends BaseController
{
/**
* "/user/list" Endpoint - Get list of users
*/
public function listAction()
{
$strErrorDesc = '';
$requestMethod = $_SERVER["REQUEST_METHOD"];
$arrQueryStringParams = $this->getQueryStringParams();
if (strtoupper($requestMethod) == 'GET') {
try {
$userModel = new UserModel();
$intLimit = 10;
if (isset($arrQueryStringParams['limit']) && $arrQueryStringParams['limit']) {
$intLimit = $arrQueryStringParams['limit'];
}
$arrUsers = $userModel->getUsers($intLimit);
$responseData = json_encode($arrUsers);
} catch (Error $e) {
$strErrorDesc = $e->getMessage().'Something went wrong! Please contact support.';
$strErrorHeader = 'HTTP/1.1 500 Internal Server Error';
}
} else {
$strErrorDesc = 'Method not supported';
$strErrorHeader = 'HTTP/1.1 422 Unprocessable Entity';
}
// send output
if (!$strErrorDesc) {
$this->sendOutput(
$responseData,
array('Content-Type: application/json', 'HTTP/1.1 200 OK')
);
} else {
$this->sendOutput(json_encode(array('error' => $strErrorDesc)),
array('Content-Type: application/json', $strErrorHeader)
);
}
}
}
值得注意的是,UserController 类扩展了BaseController 类。理想情况下,这个类将包含与为用户实体定义的REST端点相关的动作方法。例如,在我们的案例中,/user/list REST端点对应的是listAction 方法。通过这种方式,你也可以为其他REST端点定义其他方法。
listAction 方法是用来从MySQL数据库中获取用户列表的。它包含了/user/list REST端点的整个逻辑。
在listAction 方法中,我们首先初始化了几个变量,如$requestMethod 和$arrQueryStringParams 。接下来,我们检查用户是否已经用GET 方法调用了user/list 端点,否则我们不会进一步处理。最后,我们创建UserModel 对象,并调用getUsers 方法,从数据库中获取用户列表。我们还使用了json_encode 函数,在发送给用户之前将数组转换为JSON对象。
最后,我们使用sendOutput 方法向用户发送JSON响应。值得注意的是,由于我们发送的是JSON响应,所以响应的内容类型头值被设置为application/json 。
同样地,你也可以为其他端点定义其他方法。
index.php文件
index.php文件是我们应用程序的入口。让我们看看它的外观。
<?php
require __DIR__ . "/inc/bootstrap.php";
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$uri = explode( '/', $uri );
if ((isset($uri[2]) && $uri[2] != 'user') || !isset($uri[3])) {
header("HTTP/1.1 404 Not Found");
exit();
}
require PROJECT_ROOT_PATH . "/Controller/Api/UserController.php";
$objFeedController = new UserController();
$strMethodName = $uri[3] . 'Action';
$objFeedController->{$strMethodName}();
?>
首先,我们使用parse_url 和explode 函数来初始化URI段到$uri 数组变量中。接下来,我们对URI段进行验证。最后,我们已经初始化了UserController 控制器并调用了相应的动作方法。
就这样,我们已经在我们的演示REST应用程序中创建了所有必要的文件。在下一节,我们将看到如何从终端用户的角度来调用它。
如何调用我们的REST API
在本节中,我们将看到如何调用我们的演示应用程序。在我们的应用程序中,我们已经建立了一个REST端点来获取用户的列表。
让我们看看我们的端点的URL是怎样的。
// https://localhost/index.php/{MODULE_NAME}/{METHOD_NAME}?limit={LIMIT_VALUE}
http://localhost/index.php/user/list?limit=20
如果你能回忆一下index.php文件,我们检查了如果$uri[2] 变量被设置为user 。另外,$uri[3] 变量值将作为一个方法名称。在上述案例中,$uri[3] 变量被设置为list 。因此,它最终会调用UserController 类的listAction 方法。
输出结果应该是这样的。
[
{
"user_id":1,
"username":"Bob",
"user_email":"bob@gmail.com",
"user_status":0
},
{
"user_id":2,
"username":"John",
"user_email":"john@gmail.com",
"user_status":1
},
{
"user_id":3,
"username":"Mark",
"user_email":"mark@gmail.com",
"user_status":1
},
{
"user_id":4,
"username":"Ville",
"user_email":"ville@gmail.com",
"user_status":0
}
]
正如你所看到的,它以JSON对象的形式返回一个用户列表。除此之外,如果有任何应用程序的错误,它也会以JSON对象的形式返回,以便调试。
总结
今天,我们讨论了如何用PHP和MySQL建立一个REST应用程序。为了演示,我们创建了一个演示应用程序,它允许你通过REST API从MySQL数据库中获取一个用户列表。