V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
caoyangmin
V2EX  ›  PHP

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

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

    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   ·   实用小工具   ·   832 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 22:05 · PVG 06:05 · LAX 14:05 · JFK 17:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.