PhpBoot 入门(一) 快速开发 RESTful 接口 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
caoyangmin
V2EX    PHP

PhpBoot 入门(一) 快速开发 RESTful 接口

  •  
  •   caoyangmin 2017-08-15 23:07:41 +08:00 3683 次点击
    这是一个创建于 3054 天前的主题,其中的信息可能已经有所发展或是发生改变。

    PhpBoot 是一款为快速开发 RESTful API 而设计的 PHP 框架(更多内容请前往 PbpBoot Github)。本文为你演示如何使用 PhpBoot 快速开发一套 RESTful 风格的接口。

    关于 RESTful

    当 RESTful 已经不是新鲜的名词了,抛开抽象的定义,我认为一个通俗的解释可以是:按文件系统的方式去设计接口,即把接口提供的功能,当做是对“目录”的“操作”。比如一个登录接口,按 RESTful 设计,可以是POST /tokens/,即把登录,当做新建一个令牌,这里的/tokens/就是“目录”,POST就是对目录的“操作”。关于 RESTful 比较准确的定义,可以看这里。关于 RESTful 最佳实践,可以看这里

    示例接口

    下面我将演示如何用 PhpBoot 编写一组“图书管理”接口,这些接口包括:

    接口名 METHOD URI 请求示例 响应示例
    查询图书 GET /books/ GET /books/?name=php&offset=0&limit=1 {
    "total": 0,
    "data": [
    {
    "id": 0,
    "name": "string",
    "brief": "string",
    "pictures": [
    "string"
    ]
    }
    ]
    }
    获取图书详情 GET /books/{id} GET /books/1 {
    "id": 0,
    "name": "string",
    "brief": "string",
    "pictures": [
    "string"
    ]
    }
    新建图书 POST /books/ POST /books/

    {
    "id": 0,
    "name": "string",
    "brief": "string",
    "pictures": [
    "string"
    ]
    }
    123
    删除图书 DELETE /books/{id} DELETE /books/1

    项目目录结构

    • app
      • Controllers
        • Books.php 接口实现
      • Entities
        • Book.php 数据实体定义
    • config
      • config.php 配置
    • public
      • index.php 入口
    • vendor 依赖包

    入口

    index.php 作为项目入口, 通常只需要指定配置文件和 Controllers 目录的路径即可。最终项目对外提供的接口, 由不同的 Controllers 的实现类提供。

    <?php require __DIR__.'/../vendor/autoload.php'; use PhpBoot\Application; $app = Application::createByDefault(__DIR__.'/../config/config.php'); //扫描 Controllers 目录,自动加载所有路由 $app->loadRoutesFromPath( __DIR__.'/../App/Controllers', 'App\\Controllers'); //执行请求 $app->dispatch(); 

    接口实现

    定义 Book 实体

    为了在不同接口间共享“图书信息”的数据结构,我们定义一个实体如下:

    class Book { /** * @var int */ public $id; /** * 书名 * @var string */ public $name=''; /** * 简介 * @var string */ public $brief=''; /** * 图片 url * @var string[] */ public $pictures=[]; } 

    定义 Controller

    这里定义了 Books 类作为 Controller,后续接口将实现在此 Books 类中。

    /** * 提供图书管理接口 * @path /books/ */ class Books { } 

    上述代码中的注释@path /books/ 表示 Books 下所有接口,都使用 /books/ 作为前缀。

    查询图书接口

    /** * 查询图书 * * @route GET / * * @param string $name 查找书名 * @param int $offset 结果集偏移 {@v min:0} * @param int $limit 返回结果最大条数 {@v max:1000} * @param int $total 总条数 * @throws BadRequestHttpException 参数错误 * @return Book[] 图书列表 */ public function findBooks($name, &$total, $offset=0, $limit=100) { $total = 1; return [new Book()]; } 

    为便于理解,这段代码只是返回了一组固定的数据,真实场景下应该还会访问数据库或者缓存。下面将说明这段代码的工作方式:

    1. @route 定义了此接口的路由,即 GET /books/(加上了 @path 定义的前缀)。

    2. @param 定义了接口的请求参数和类型,如果不声明@param, 接口参数将从函数定义中提取, 如果函数定义中没有申明参数类型,则参数类型被认为是 mixed。

    3. @v 定义了参数的取值范围,若不指定,框架将只会校验请求中的参数类型, 即如果参数是类型是 int,则请求中参数必须是可以转换成 int 的类型,如 123 或者"123"等,否则会返回 400 错误

    4. 函数的返回值将被 json_encode 后输出到 body。如果函数的参数中没有引用类型(引用类型的参数被认为是输出,而不是输入),return 在 json_encode 后即被当做 body 输出,否则 return 将被赋值给 body 中的 ” data “。

    5. &$total 是引用类型的参数,会被最为输出,默认输出到 body 中同名变量中。如这个接口中,最终输出的 body 形式如下:

      { "total": 1, //来自 &$total "data": [ //来自 return { "id": 0, "name": "string", "brief": "string", "pictures": [ "string" ] } ] } 
    6. 如果希望将 return 输出到其他位置,或者不使用默认的输入参数绑定方式,可以使用@bind, 比如 @return Book[] 图书列表 {@bind response.content.books} 将使 return 结果绑定在 json 的 "books" 上,而不是默认的 "data"。

    7. $offset=0, $limit=100定义了默认值,如果请求中不包含这些参数,将使用默认值。

    8. 注释 @return Book[]@throws BadRequestHttpException 并不会对接口的返回有任何影响, 而只会影响文档输出和远程调用( RPC )。

    获取图书详情接口

    /** * 获取图书 * @route GET /{id} * * @param string $id 指定图书编号 * * @throws NotFoundHttpException 图书不存在 * * @return Book 图书信息 */ public function getBook($id) { return new Book(); } 

    路由 @route GET /{id} 指定了 url 的 path 有一个变量{id},变量的值可以通过函数参数 @id 获取

    新建图书

    /** * 新建图书 * * @route POST / * @param Book $book {@bind request.request} 这里将 post 的内容绑定到 book 参数上 * @throws BadRequestHttpException * @return string 返回新建图书的编号 */ public function createBook(Book $book) { return '123'; } 
    1. 请求中的 json 会被框架自动转换成函数中需要的对象参数。
    2. {@bind request.request} 表示用请求的 body 构造 $book 变量,若不指定 @bind,默认是提取请求 body 中 "book" 字段构造 $book 变量,也就是说请求会是以下形式:
    { "book": { "id": 0, "name": "string", "brief": "string", "pictures": [ "string" ] } } 

    删除图书

    /** * 删除图书 * * @route DELETE /{id} * @param string $id * @throws NotFoundHttpException 指定图书不存在 * @return void */ public function deleteBook($id) { } 

    如果函数没有返回值,则响应的 http body 会是 void, 而不是空字符串, 因为 基于 PhpBoot 实现的接口,默认情况下,http body 总是 json,而空字符串并不是合法的 json。

    更多

    更多内容见:

    下期将介绍 PhpBoot 数据库部分的使用,敬请期待。

    如需帮助可以联系 [email protected] ,或者加入 QQ 群:185193529

    junred
        1
    junred  
       2017-08-16 09:19:55 +08:00
    设计上看上去还可以
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2683 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 37ms UTC 15:15 PVG 23:15 LAX 07:15 JFK 10:15
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86