Restful API实战来源:Restful API实战教程-慕课网 (imooc.com)
目录
项目需求
用户登录、注册
文章发表、查看、编辑、删除、列表
1、确认设计要素
资源路径:/users、/articles
HTTP动词:GET、POST、DELETE、PUT
过滤信息:文章的分页筛选
状态码:200、204、400、401、403、404、405、500
错误处理:输出JSON格式错误信息
返回结果:输出JSON数组或JSON对象
2、数据库设计
用户表:
用户ID、用户名、密码、注册时间
文章表:
文章ID、标题、内容、发表时间、用户ID(外键)
/*
* foreign key(user_id) references user(user_id)
* 这行代码可能有问题,没起作用。
*/
create table `user`(
`user_id` int unsigned primary key auto_increment,
`username` varchar(10) not null unique,
`password` char(32) not null,
`created_at` datetime not null
)charset=utf8;
create table `article`(
`article_id` int unsigned primary key auto_increment,
`title` varchar(40) not null,
`content` text not null,
`created_at` datetime not null,
`user_id` int,
foreign key(user_id) references user(user_id)
)charset=utf8;
tips:学习下“SQL索引、SQL约束”知识。
3、架构
lib:
- db.php(连接数据库并返回数据库连接句柄)
- User.php(连接数据库、 用户登录、用户注册、MD5加密 )
- ErrorCode.php(定义类常量)
- Article.php(连接数据库、创建文章、查看一篇文章、编辑文章、删除文章、获取文章列表)
inde x.php(测试用户业务逻辑、文章业务逻辑)
Restful:
-
.htaccess(初始化运行参数)
-
index.php(用户API、文章API)
4、代码
第一步:完成可共用部分的代码。lib中的:用户业务逻辑、文章业务逻辑。在api.com目录下的index.php中进行测试。
第二步:完成RESTful API部分的代码。Restful中的:初始化运行参数、完善用户API、文章API。
lib:
(1)db.php
<?php
//连接数据库
$pdo=new PDO('mysql:host=127.0.0.1;dbname=restful;','root','root');
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);//数据库里存的是什么类型,PDO查出来的就是什么类型。
//返回数据库连接句柄
return $pdo;
注意:
链接数据库我本来用的是:$pdo=new PDO('mysql:host=localhost;dbname=restful;','root','root');
刚开始用的好好的,后面突然就报错:Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000] [1045] Access denied for user 'root'@'localhost' (using password: YES)' in ...
我也不知道咋回事,反正改成:$pdo=new PDO('mysql:host=127.0.0.1;dbname=restful;','root','root'); 就又能用了。
(2)User.php
功能概述:连接数据库、 用户登录、用户注册、MD5加密
连接数据库(数据库连接句柄)
1、构造方法
用户登录(用户名、密码)
1、验证传入的参数
- 用户名、密码不能为空的验证
2、验证用户名、密码是否匹配
- $sql语句
- 预处理
- 绑定参数
- 执行(执行失败,抛出错误:“服务器内部错误”。)
- 获取执行结果(获取的数据为空,抛出错误:“用户名或密码错误”。)
- 返回数据(删除密码字段后再返回。)
用户注册(用户名、密码)
1、验证传入的参数
- 用户名、密码不能为空的验证
- 用户名的唯一性验证
2、写入数据库
- $sql语句
- 预处理
- 绑定参数
- 执行(执行失败,抛出错误:“注册失败”。)
- 返回数据(return数组形式返回数据,不要返回密码。)
MD5加密
<?php
/**
* 实现用户登录注册的业务逻辑设计
*/
require_once __DIR__.'/ErrorCode.php';
class User
{
/**
* 数据库连接句柄
* @var
*/
private $_db;
/**
* 构造方法
* @param PDO $_db 数据库连接句柄
*/
public function __construct($_db)
{
$this->_db=$_db;
}
/**
* 用户登录
* @param $username
* @param $password
* @return mixed
* @throws Exception
*/
public function login($username,$password)
{
if(empty($username)){
throw new Exception('用户名不能为空',ErrorCode::USERNAME_CANNOT_EMPTY);
}
if(empty($password)){
throw new Exception('密码不能为空',ErrorCode::PASSWORD_CANNOT_EMPTY);
}
$sql="select * from `users` where `username`=:username and `password`=:password";
$password=$this->_md5($password);
$stmt=$this->_db->prepare($sql);
$stmt->bindParam(':username',$username);
$stmt->bindParam(':password',$password);
if(!$stmt->execute()){
throw new Exception('服务器内部错误',ErrorCode::SERVER_INTERNAL_ERROR);
}
$user=$stmt->fetch(PDO::FETCH_ASSOC);
if(empty($user)){
throw new Exception('用户名或密码错误',ErrorCode::USERNAME_OR_PASSWORD_INVALID);
}
unset($user['password']);//删除用户密码字段后再将用户信息返回。
return $user;
}
/**
* 用户注册
* @param $username
* @param $password
* @return array
* @throws Exception
*/
public function register($username,$password)
{
if(empty($username)){
throw new Exception('用户名不能为空',ErrorCode::USERNAME_CANNOT_EMPTY);
}
if(empty($password)){
throw new Exception('密码不能为空',ErrorCode::PASSWORD_CANNOT_EMPTY);
}
if($this->_isUsernameExists($username)){
throw new Exception('用户名已存在',ErrorCode::USERNAME_EXISTS);
}
//写入数据库
$sql="insert into `users`(`username`,`password`,`created_at`) values (:username,:password,:created_at)";
$created_at=time();
$password=$this->_md5($password);
$stmt=$this->_db->prepare($sql);
$stmt->bindParam(':username',$username);
$stmt->bindParam(':password',$password);
$stmt->bindParam(':created_at',$created_at);
if(!$stmt->execute()){
throw new Exception('用户注册失败',ErrorCode::REGISTER_FAIL);
}
return[
'user_id'=>$this->_db->lastInsertId(),
'username'=>$username,
'created_at'=>$created_at
];
}
/**
* MD5加密
* @param $string
* @param string $key
* @return string
*/
public function _md5($string, $key='imooc'){
return md5($string.$key);
}
/**
* 检测用户名是否存在
* @param $username
* @return bool
*/
public function _isUsernameExists($username)
{
$sql = "select * from `users` where `username`=:username";//:username,占位符,防止SQL注入
//返回预处理
$stmt = $this->_db->prepare($sql);
//绑定参数
$stmt->bindParam(':username',$username);
//执行
$stmt->execute();
//获取执行结果,以关联数组形式返回
$res = $stmt->fetch(PDO::FETCH_ASSOC);
return !empty($res);
}
}
注意1:__construct前面是“两个”下划线。这里若是写错了,就会这么报错:Fatal error: Call to a member function prepare() on a non-object in ...
碎碎念:
能这样写错的,估计也没几个。。。
我是真的伤心,以为是pdo加载有问题,各种百度答案试了个遍。破罐子破摔着往后写,后来才发现是构造方法的__construct写成了_construct。。。
注意2:突然对 if(!$stmt->execute()) 产生了疑惑。
if(!$stmt->execute()){ }
if否,则执行{ }里的内容;if真,$stmt->execute()执行了吗?
做了验证,其实这里应该是:$res=$stmt->execute(); if(!$res){ }
(3)ErrorCode.php
<?php
/**
* 错误码
*/
class ErrorCode
{
const USERNAME_CANNOT_EMPTY=1;//用户名不能为空
const PASSWORD_CANNOT_EMPTY=2;//密码不能为空
const USERNAME_EXISTS=3;//用户名已存在
const REGISTER_FAIL=4;//用户注册失败
const USERNAME_OR_PASSWORD_INVALID=5;//用户名或密码错误
//文章标题不能为空
const ARTICLE_TITLE_CANNOT_EMPTY=6;
//文章内容不能为空
const ARTICLE__CONTENT_CANNOT_EMPTY=7;
//发表文章失败
const ARTICLE_CREATE_FAIL=8;
//文章ID不能为空
const ARTICLE_ID_CANNOT_EMPTY=9;
//文章不存在
const ARTICLE_NOT_FOUND=10;
//您无权编辑该文章
const PERMISSION_DENIED=11;
//文章编辑失败
const ARTICLE_EDIT_FAIL=12;
//文章删除失败
const ARTICLE_DELETE_FAIL=13;
//分页大小最大为100
const PAGE_SIZE_TO_BIG=14;
//服务器内部错误
const SERVER_INTERNAL_ERROR=15;
}
(4)Article.php
功能概述:连接数据库、创建文章、查看一篇文章、编辑文章、删除文章、获取文章列表
连接数据库(数据库连接句柄)
1、构造方法
创建文章(文章标题、文章内容、用户ID)
1、验证传入的参数
- 文章标题、内容不能为空的验证
2、写入数据库
- $sql语句
- 预处理
- 绑定参数
- 执行(执行失败,抛出错误“文章发表失败”。)
- 返回数据(return数组形式返回数据。)
查看一篇文章(文章ID)
1、验证传入的参数
- 文章ID不能为空的验证
2、根据文章ID查询文章
- $sql语句
- 预处理
- 绑定参数
- 执行
- 获取执行结果(获取的数据为空,抛出错误:“文章不存在”。)
- 返回数据
编辑文章(文章ID、用户ID、文章标题、文章内容)
1、查看文章是否存在。
2、验证权限。(如果文章ID、用户ID不匹配,抛出错误:“您无权编辑该文章”。)
3、验证传入的文章标题、文章内容。
- 如果文章标题,使用原文章标题;如果文章内容为空,使用原文章内容。
- 如果文章标题为原文章标题 且 文章内容为原文章内容,直接返回原文章数据,不用再更新文章。
4、更新文章
- $sql语句
- 预处理
- 绑定参数
- 执行(执行失败,抛出错误“文章编辑失败”。)
- 返回数据(return数组形式返回数据。)
删除文章(文章ID、用户ID)
1、查看文章是否存在。
2、验证权限。(如果文章ID、用户ID不匹配,抛出错误:“您无权操作该文章”。)
3、删除文章
- $sql语句
- 预处理
- 绑定参数
- 执行(执行失败,抛出错误“文章删除失败”。)
- 返回true
获取文章列表(用户ID、页码默认值、页面显示数据条数默认值)
1、对页面显示数据条数进行限制。
2、计算limit的第一个参数,并做容错处理。(limit的第1个参数=(页码-1)*页面显示数据条数)
3、根据用户ID查询文章
- $sql语句
- 预处理
- 绑定参数
- 执行(执行失败,抛出错误“文章删除失败”。)
- 获取执行结果(获取的数据不止一条,使用fetchAll)
- 返回数据
<?php
/**
* 实现文章增删改查的业务逻辑设计
*/
require_once __DIR__.'/ErrorCode.php';
class Article
{
/**
* 数据库连接句柄
* @var
*/
private $_db;
/**
* 构造方法
* @param PDO $_db 数据库连接句柄
*/
public function __construct($_db)
{
$this->_db=$_db;
}
/**
* 创建文章
* @param $title
* @param $content
* @param $user_id
* @return array
* @throws Exception
*/
public function create($title,$content,$user_id)
{
if(empty($title)){
throw new Exception('文章标题不能为空',ErrorCode::ARTICLE_TITLE_CANNOT_EMPTY);
}
if(empty($content)){
throw new Exception('文章内容不能为空',ErrorCode::ARTICLE__CONTENT_CANNOT_EMPTY);
}
$sql="insert into `article` (`title`,`content`,`created_at`,`user_id`) values (:title,:content,:created_at,:user_id)";
$created_at=time();
$stmt=$this->_db->prepare($sql);
$stmt->bindParam(':title',$title);
$stmt->bindParam(':content',$content);
$stmt->bindParam(':created_at',$created_at);
$stmt->bindParam(':user_id',$user_id);
if(!$stmt->execute()){
throw new Exception('文章发表失败',ErrorCode::ARTICLE_CREATE_FAIL);
}
return[
'article_id'=>$this->_db->lastInsertId(),
'title'=>$title,
'content'=>$content,
'created_at'=>$created_at,
'user_id'=>$user_id
];
}
/**
* 查看一篇文章
* @param $article_id
* @return mixed
* @throws Exception
*/
public function view($article_id)
{
if(empty($article_id)){
throw new Exception('文章ID不能为空',ErrorCode::ARTICLE_ID_CANNOT_EMPTY);
}
$sql="select * from `article` where `article_id`=:article_id";
$stmt=$this->_db->prepare($sql);
$stmt->bindParam(':article_id',$article_id);
$stmt->execute();
$article=$stmt->fetch(PDO::FETCH_ASSOC);
if(empty($article)){
throw new Exception('文章不存在',ErrorCode::ARTICLE_NOT_FOUND);
}
return $article;
}
/**
* 编辑文章
* @param $article_id
* @param $title
* @param $content
* @param $user_id
* @return array|mixed
* @throws Exception
*/
public function edit($article_id,$user_id,$title,$content)
{
$article=$this->view($article_id);
if($article['user_id']!=$user_id){
throw new Exception('您无权编辑该文章',ErrorCode::PERMISSION_DENIED);
}
$title=empty($title)?$article['title']:$title;
$content=empty($content)?$article['content']:$content;
if(($title==$article['title'])&&($content==$article['content'])){
return $article;
}
$sql="update `article` set `title`=:title,`content`=:content where `article_id`=:article_id";
$stmt=$this->_db->prepare($sql);
$stmt->bindParam(':title',$title);
$stmt->bindParam(':content',$content);
$stmt->bindParam(':article_id',$article_id);
if(!$stmt->execute()){
throw new Exception('文章编辑失败',ErrorCode::ARTICLE_EDIT_FAIL);
}
return[
'article_id'=>$article_id,
'title'=>$title,
'content'=>$content,
'created_at'=>$article['created_at']
];
}
/**
* 删除文章
* @param $article_id
* @param $user_id
* @return bool
* @throws Exception
*/
public function delete($article_id,$user_id)
{
$article=$this->view($article_id);
if($article['user_id']!=$user_id){
throw new Exception('您无权操作该文章',ErrorCode::PERMISSION_DENIED);
}
$sql="delete from `article` where `article_id`=:article_id and `user_id`=:user_id";
$stmt=$this->_db->prepare($sql);
$stmt->bindParam(':article_id',$article_id);
$stmt->bindParam(':user_id',$user_id);
if(false===$stmt->execute()){
throw new Exception('文章删除失败',ErrorCode::ARTICLE_DELETE_FAIL);
}
return true;
}
/**
* 获取文章列表
* @param $user_id
* @param int $page
* @param int $size
* @return mixed
* @throws Exception
*/
public function getList($user_id,$page=1,$size=10)
{
if($size>100){
throw new Exception('分页大小最大为100',ErrorCode::PAGE_SIZE_TO_BIG);
}
$sql="select * from `article` where `user_id`=:user_id limit :limit,:offset";
$limit=($page-1)*$size;
$limit=$limit<0?0:$limit;
$stmt=$this->_db->prepare($sql);
$stmt->bindParam(':user_id',$user_id);
$stmt->bindParam(':limit',$limit);
$stmt->bindParam(':offset',$size);
$stmt->execute();
$data=$stmt->fetchAll(PDO::FETCH_ASSOC);
return $data;
}
}
index.php
<?php
//错误信息
ini_set('display_errors',1);
//php启动错误信息
ini_set('display_startup_errors',1);
//打印出所有的错误信息
error_reporting(-1);
require __DIR__.'/lib/User.php';
require __DIR__.'/lib/Article.php';
$pdo = require __DIR__.'/lib/db.php';
$user = new User($pdo);
//检测用户名是否存在
//print_r($user->register('admin','123456'));
//验证用户注册业务逻辑
//print_r($user->register('admin1','123456'));
//验证用户登录业务逻辑
//print_r($user->login('admin','123456'));
$article = new Article($pdo);
//验证创建文章业务逻辑
//print_r($article->create('文章标题','文章内容','7'));
//验证查看一篇文章业务逻辑
//print_r($article->view('1'));
//验证编辑文章业务逻辑
//print_r($article->edit('1','文章标题1','文章内容1','7'));
//验证删除文章业务逻辑
//var_dump($article->delete(3,3));
//验证获取文章列表业务逻辑
//print_r($article->getList(7));
//print_r($article->getList(7,1,1));
显示php报错信息:(放在入口文件处即可)
//错误信息
ini_set('display_errors',1);
//php启动错误信息
ini_set('display_startup_errors',1);
//打印出所有的错误信息
error_reporting(-1);
Restful:
(1).htaccess
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [L]
(2)index.php
<?php
//print_r($_SERVER);
require __DIR__.'/../lib/User.php';
require __DIR__.'/../lib/Article.php';
$pdo = require __DIR__.'/../lib/db.php';
class Restful
{
/**
* @var User
*/
private $_user;
/**
* @var Article
*/
private $_article;
/**
* 请求方法
* @var string
*/
private $_requestMethod;
/**
* 请求的资源名称
* @var string
*/
private $_resourceName;
/**
* 请求的资源ID
* @var string
*/
private $_resourceId;
/**
* 允许请求的HTTP方法
* @var array
*/
private $_allowRequestMethods=['GET','POST','PUT','DELETE','OPTIONS'];
/**
* 允许请求的资源列表
* @var array
*/
private $_allowResources=['users','articles'];
/**
* 常用状态码
* @var array
*/
private $_statusCodes=[
200=>'Ok',
204=>'No Content',
400=>'Bad Request',
401=>'Unauthorized',
403=>'Forbidden',
404=>'Not Found',
405=>'Method Not Allowed',
500=>'Server Internal Error'
];
/**
* Restful constructor
* @param User $_user
* @param Article $_article
*/
public function __construct(User $_user,Article $_article)
{
$this->_user=$_user;
$this->_article=$_article;
}
public function run()
{
try{
$this->_setupRequestMethod();//初始化请求方式
$this->_setupResource();//初始化请求资源
//进行具体的业务逻辑处理(面向对象)
if($this->_resourceName=='users'){
$this->_json($this->_handleUser());
}else{
$this->_json($this->_handleArticle());
}
}catch (Exception $e){
$this->_json(['error'=>$e->getMessage()],$e->getCode());
}
}
/**
* 初始化请求方法
*/
private function _setupRequestMethod()
{
$this->_requestMethod=$_SERVER['REQUEST_METHOD'];
if(!in_array($this->_requestMethod,$this->_allowRequestMethods)){
throw new Exception('请求方法不被允许',405);
}
}
/**
* 初始化请求资源
*/
private function _setupResource()
{
$path=$_SERVER['PATH_INFO'];
//echo $path;
$params=explode('/',$path);
//print_r($params);
$this->_resourceName=$params[1];
if(!in_array($this->_resourceName,$this->_allowResources)){
throw new Exception('请求资源不被允许',400);
}
if(!empty($params[2])){
$this->_resourceId=$params[2];
}
}
/**
* 输出JSON
* @param $array
* @param int $code
*/
private function _json($array,$code=0)
{
/*
if($code>0 && $code!=200 && $code!=204){
header("HTTP/1.1 ".$code." ".$this->_statusCodes[$code]);//注意:HTTP/1.1后面有一个空格
}
*/
if($array===null && $code===0){
$code=204;
}
if($array!==null && $code===0){
$code=200;
}
header("HTTP/1.1 ".$code." ".$this->_statusCodes[$code]);
header('Content-Type:application/json;charset=utf-8');
if($array!==null){
echo json_encode($array,JSON_UNESCAPED_UNICODE);
}
exit();
}
/**
* 请求用户
* @return array
* @throws Exception
*/
private function _handleUser()
{
if($this->_requestMethod!='POST'){
throw new Exception('请求方法不被允许',405);
}
$body=$this->_getBodyParams();
if(empty($body['username'])){
throw new Exception('用户名不能为空',400);
}
if(empty($body['password'])){
throw new Exception('密码不能为空',400);
}
return $this->_user->register($body['username'],$body['password']);
}
/**
* 请求文章资源
*/
private function _handleArticle()
{
switch($this->_requestMethod){
case 'POST':
return $this->_handleArticleCreate();
case 'PUT':
return $this->_handleArticleEdit();
case 'DELETE':
return $this->_handleArticleDelete();
case 'GET':
if(empty($this->_resourceId)){
return $this->_handleArticleList();
}else{
return $this->_handleArticleView();
}
default:
throw new Exception('请求方法不被允许',405);
}
}
/**
* 获取请求参数
* @return mixed
* @throws Exception
*/
private function _getBodyParams()
{
$raw=file_get_contents('php://input');
if(empty($raw)){
throw new Exception('请求参数错误',400);
}
return json_decode($raw,true);
}
/**
* 创建文章
* @return array
* @throws Exception
*/
private function _handleArticleCreate()
{
$body=$this->_getBodyParams();
if(empty($body['title'])){
throw new Exception('文章标题不能为空',400);
}
if(empty($body['content'])){
throw new Exception('文章内容不能为空',400);
}
$user=$this->_userLogin($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW']);
try{
$article=$this->_article->create($body['title'],$body['content'],$user['user_id']);
return $article;
}catch (Exception $e){
if(in_array($e->getCode(),
[
ErrorCode::ARTICLE_TITLE_CANNOT_EMPTY,
ErrorCode::ARTICLE__CONTENT_CANNOT_EMPTY
])){
throw new Exception($e->getMessage(),400);
}
throw new Exception($e->getMessage(),500);
}
}
/**
* 编辑文章
* @return array|mixed
* @throws Exception
*/
private function _handleArticleEdit()
{
$user=$this->_userLogin($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW']);
try{
$article=$this->_article->view($this->_resourceId);//$this->_id
if($article['user_id']!=$user['user_id']){
throw new Exception('您无权编辑该文章',403);
}
$body=$this->_getBodyParams();
$title=empty($body['title'])?$article['title']:$body['title'];
$content=empty($body['content'])?$article['content']:$body['content'];
if($title==$article['title'] && $content==$article['content']){
return $article;
}
return $this->_article->edit($article['article_id'],$title,$content,$user['user_id']);
}catch (Exception $e){
if($e->getCode()<100){
if($e->getCode()==ErrorCode::ARTICLE_NOT_FOUND){
throw new Exception($e->getMessage(),404);
}else{
throw new Exception($e->getMessage(),400);
}
}else{
throw $e;
}
}
}
/**
* 删除文章
* @return null
* @throws Exception
*/
private function _handleArticleDelete()
{
$user=$this->_userLogin($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW']);
try{
$article=$this->_article->view($this->_resourceId);//$this->_id
if($article['user_id']!=$user['user_id']){
throw new Exception('您无权操作',403);
}
$this->_article->delete($article['article_id'],$user['user_id']);
return null;
}catch (Exception $e){
if($e->getCode()<100){
if($e->getCode()==ErrorCode::ARTICLE_NOT_FOUND){
throw new Exception($e->getMessage(),404);
}else{
throw new Exception($e->getMessage(),400);
}
}else{
throw $e;
}
}
}
/**
* 文章分页
* @return mixed
* @throws Exception
*/
private function _handleArticleList()
{
$user=$this->_userLogin($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW']);
$page=isset($_GET['page'])?$_GET['page']:1;
$size=isset($_GET['size'])?$_GET['size']:10;
if($size>100){
throw new Exception('分页大小最大为100',400);
}
return $this->_article->getList($user['user_id'],$page,$size);
}
/**
* 查看文章
* @return mixed
* @throws Exception
*/
private function _handleArticleView()
{
try{
return $this->_article->view($this->_resourceId);
}catch (Exception $e){
if($e->getCode()==ErrorCode::ARTICLE_NOT_FOUND){
throw new Exception($e->getMessage(),404);
}else{
throw new Exception($e->getMessage(),500);
}
}
}
/**
* 用户登录
* @param $PHP_AUTH_USER
* @param $PHP_AUTH_PW
* @return mixed
* @throws Exception
*/
private function _userLogin($PHP_AUTH_USER,$PHP_AUTH_PW)
{
try{
return $this->_user->login($PHP_AUTH_USER,$PHP_AUTH_PW);
}catch (Exception $e){
if(in_array($e->getCode(),
[
ErrorCode::USERNAME_CANNOT_EMPTY,
ErrorCode::PASSWORD_CANNOT_EMPTY,
ErrorCode::USERNAME_OR_PASSWORD_INVALID
])){
throw new Exception($e->getMessage(),401);
}
throw new Exception($e->getMessage(),500);
}
}
}
$user = new User($pdo);
$article = new Article($pdo);
$restful = new Restful($user,$article);
$restful->run();