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

Laravel 开发 RESTful API 的心得

  •  1
     
  •   DavidNineRoc · 2018-03-01 23:17:46 +08:00 · 4395 次点击
    这是一个创建于 2455 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近用 Laravel 写了一段时间的 API,总结一下自己的心得吧。

    Start

    • API开发我们可以看到,有些网站用token验证身份,有些用OAuth2.0,当时我也纠结,然后看到一个不错的说法。大方面,会涉及到给别人用的使用OAuth,自己使用的用token就足够了
    • 设计最初,最好在路由加个版本号,方便以后扩展
    Route::prefix('v1')->group(function () {
    	// more
    });
    

    一个简单的接口示例 api 实例输出

    验证

    • API 开发总会离不开验证,这里推荐使用jwt-auth,1.0 快要来了,新版本的文档也很清晰
    • 刚用jwt-auth时有疑问,Laravel自带的token验证使用的是数据库api_token字段验证,而不见jwt-auth需要这个
      • 然后想自己看源码,结果QAQ
      • 最后去问了官方 >_<
      • 原来用户的信息已经存储在token中加密
      • 一开始有疑问,这样保存,不会被解密吗(真为自己智商担忧 !_!)
      • 后来才想起,jwt一开始就运行php artisan jwt:secret生成了秘钥
      • 你不泄露就保证安全了~~~

    路由

    • 当然使用官方api的路由Route::apiResource(),一条更比五条强
    • 路由的名字当然是RESTful的方式
    • 保持动词,复数形式,见名知义
    • 有些长的路由,应该用什么分隔呢?
    • laravel用的是中划线(-),因为谷歌收录时,按中划线划分关键字,国内的是按下划线(_)收录,具体看自己了,我是喜欢下划线 >_<
    • 更多看这里: 路由命名规范

    表单验证

    可以使用控制器自带的表单验证,更推荐使用 表单类,能分离都分离出去,控制器不要处理太多事情。 表单验证 能分离的代码都不要吝啬~~~

    数据转换

    • Laravel自带的API Resource
    • 用起来真的很方便,不过发现一个问题,--collection的格式总是转不过来,后来直接放弃了
    • 单个的使用Resources
    • 集合的使用Resources::collection()发现,特别好用 >_<
    • 不得不说,多对多关联时,Laravel处理得太好了条件关联 数据转换
    • 在上面这个例子中,如果关联没有被加载,则 posts 键将会在资源响应被发送给客户端之前被删除。
    • 在有不确定是否输出关联数据时,这是一个很有用的功能!!!

    响应输出

    当时在 laravel-china 看到的这个帖子,然后觉得这个方式不错,所以自己也这样子,使用基类的方法统一响应输出。

    异常

    异常算是一大手笔了,处理好异常,可以让你的代码优雅很多。 \App\Exceptions\Handler::render方法可以捕获到很多有用的异常,例如,我的代码是这样写的: 异常捕获 UnauthorizedHttpException这个是捕获jwt异常 ValidationException这个是表单异常,捕获之后,表单错误消息可以很好的格式化, ModelNotFoundException这个是模型找不到的异常,捕获之后,可以直接在控制器直接这样

    // 未捕获之前的写法
    public function show($id)
    {
    	$user = User::find($id);
    	if (! $user) {
    		
    	}
    	
    	// do something
    }
    
    // 现在
    public function show($id)
    {
    	$user = User::findOrFail($id);
    }
    // 甚至这样
    public function show(User $user)
    {
    	// do something
    }
    
    • 下面这两个异常可以不捕获,只是方便开发中查看错误消息 NotFoundHttpException404 路由找不到的异常,没什么好说的了 MethodNotAllowedHttpException这个是方法不对应,比如你是get路由,却post请求

    文档

    • 差点忘了这个,文档非常非常重要
    • 我是不怎么喜欢在注释写文档的
    • 使用swagger-ui+swagger-edit
      • 下载swagger-ui
      • 只需要dist目录的东西(其他可以删除了)
      • 下载swagger-editor
      • 只要dist目录的东西和根目录的index.html
      • 我还把swagger-editorindex.html改成了edit.html,然后把这两个东西整合到同一个目录(记得修改css,js的位置)
      • 新建两个文件api.json,api.yaml 大概就和图中差不多
      • 要修改图中箭头所示成为api.json的位置 api
    • 访问edit.html可以书写文档
    • 访问index.html可以查看文档
    • edit.html写好之后,导出json,然后粘贴到api.json文件 api
    • 记得也把写好的格式保存到api.yaml,因为清楚缓存之后,下次访问时会消失

    自己写了一个packages

    • 就方便创建控制器,验证
    • 所有控制器继承重写过的基类,响应输出方便。 laravel-api-helper
    • 例如完整验证只需要三秒钟
      • 第一秒: php artisan api:auth
      • 第二秒: 出现图代表成功; laravel-api-helper
      • 第三秒: 拿出手臂的劳力士,确定只过了三秒 手臂的手表
    • 更多的使用:laravel-api-helper

    工作和API开发有关,用到其他有经验了再回来补补。

    更多参考

    RESTful API 设计指南


    ps:用错账号发了,用这个补一下

    15 条回复    2018-03-07 11:29:32 +08:00
    johnnie502
        1
    johnnie502  
       2018-03-02 04:21:47 +08:00
    为啥要用 Laravel,这种场景是属于 Lumen 的
    tSQghkfhTtQt9mtd
        2
    tSQghkfhTtQt9mtd  
       2018-03-02 11:16:19 +08:00 via Android
    手表笑喷🤣
    DavidNineRoc
        3
    DavidNineRoc  
    OP
       2018-03-02 11:53:31 +08:00
    @johnnie502 lumen 有很多功能没有,表单分离验证,数据转换,laravel 官方文档都有 apiResource 路由,所以开发 API 妥妥的,何必省这点性能呢。玩 lumen 想用 laravel 的某些功能时,总想用什么包,或者怎么写才能实现 laravel 的一些功能,所以,花点钱买好的服务器。
    DavidNineRoc
        4
    DavidNineRoc  
    OP
       2018-03-02 11:53:51 +08:00
    @liwanglin12 需要买一个吗?童叟无欺
    carlclone
        5
    carlclone  
       2018-03-02 12:40:00 +08:00
    你需要 Laravel Passport , dingo api , JWT
    Jarvix
        6
    Jarvix  
       2018-03-02 14:30:45 +08:00
    make
    DavidNineRoc
        7
    DavidNineRoc  
    OP
       2018-03-02 14:35:06 +08:00
    @carlclone passport 得看应用场景,我觉得我完全不需要,dingo api 我觉得 lv-5.5 已经有很多功能满足了我的需求,重要的部分验证,数据转换,文档 我都觉已经足够了。
    jwt 我又写了,用的 jwt-auth,dingo 内置也是用这个,我单独使用而已
    z5864703
        8
    z5864703  
       2018-03-05 10:14:20 +08:00
    异常处理里面引入控制器来做资源返回?这样处理方式不太好吧
    DavidNineRoc
        9
    DavidNineRoc  
    OP
       2018-03-05 13:03:43 +08:00
    @z5864703 主要是为了统一处理响应,而不是直接使用 `response()`
    z5864703
        10
    z5864703  
       2018-03-05 14:03:17 +08:00
    @DavidNineRoc 那用 trait 就好了
    DavidNineRoc
        11
    DavidNineRoc  
    OP
       2018-03-05 14:12:39 +08:00
    @z5864703 trait 是无法实例化的。
    z5864703
        12
    z5864703  
       2018-03-05 17:37:55 +08:00
    @DavidNineRoc 为什么要实例化...感觉你不清楚 trait 是干嘛用的...
    DavidNineRoc
        13
    DavidNineRoc  
    OP
       2018-03-05 17:58:18 +08:00
    @z5864703 无力吐槽了,是你问我用 trait 就好了,而我告诉你 trait 无法实例化。是因为我的 ApiController 的方法来自于 trait,我这样说可否讲清楚一点了吗?
    而且你肯定没有看源码,我并不是返回 ApiController,而是通过内部的 toJson()。好吧是我没说清楚。
    https://github.com/DavidNineRoc/laravel-api-helper/blob/master/src/Services/ResponseServe.tpl#L126-L134
    z5864703
        14
    z5864703  
       2018-03-07 10:17:13 +08:00
    @DavidNineRoc 那这更有问题了,ApiController 的方法来源于写的一个 trait,那异常这里直接 use 这个 trait 就好了,还得中间再耦合一个控制器进来,不是多此一举么。和能不能实不实例化有关系么?所以我说你不清楚 trait 干嘛用的,你现在描述的和你的源码更证明了这个观点。。。
    DavidNineRoc
        15
    DavidNineRoc  
    OP
       2018-03-07 11:29:32 +08:00
    @z5864703 异常做异常该做的事,为什么返回做 json 响应呢?我使用 ApiController 是因为:当以后我改变了 ApiController 里面的代码,比如响应状态码,现在是 200 是成功,我以后要用 0 做为成功,而我用 ApiController 统一调用,以后不需要懂异常的代码
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5429 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 08:08 · PVG 16:08 · LAX 00:08 · JFK 03:08
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.