是时候使用 Lumen 7 + API Resource 开发项目了!

使用 Lumen 7 + Api Resource 进行 API 开发

写在前面

工作中使用 Laravel 开发 API 项目已经有些年头了,发现每次启动新的 Api 项目的时都会在 Laravel 基础上进行一些 预处理 ,包括针对 API 项目的结构设计,统一响应结构的封装,异常的捕获处理以及授权模块的配置等。总是在做一些重复的工作,那索性将这些常用的基础封装做成一个「启动模板」好了。

项目地址: 戳这儿

为什么是 Lumen ?

现如今,中大型项目中通常使用 前后端分离 方式开发,前后端分别通过不同的代码仓库各自维护着项目代码,Laravel 只负责项目中的 API 部分,提供 API 给前端调用。这种场景下,使用 Laravel 进行开发 API 稍微 显得有点“臃肿”了。

相比之下,Lumen 针对项目中的 API 开发场景, 精简 了Laravel 中的很多部分,更适合 API 开发。有了 Laravel 使用经验,切换到 Lumen 也较为容易。

概览

  • 适配 Laravel 7 中新增的 HttpClient 客户端
  • 使用 Laravel 原生的 Api Resource
  • 规范统一的响应结构
  • 使用 Jwt-auth 方式授权
  • 支持日志记录到 MongoDB
  • 合理有效地『Repository & Service』架构设计(:smirk:)

规范的响应结构

摘选自: RESTful 服务最佳实践

code——包含一个整数类型的HTTP响应状态码。 status——包含文本:"success","fail"或"error"。HTTP状态响应码在500-599之间为"fail",在400-499之间为"error",其它均为"success"(例如:响应状态码为1XX、2XX和3XX)。 message——当状态值为"fail"和"error"时有效,用于显示错误信息。参照国际化(il8n)标准,它可以包含信息号或者编码,可以只包含其中一个,或者同时包含并用分隔符隔开。 data——包含响应的body。当状态值为"fail"或"error"时,data仅包含错误原因或异常名称。

说明

整体响应结构设计参考如上,相对严格地遵守了 RESTful 设计准则,返回合理的 HTTP 状态码。

考虑到业务通常需要返回不同的“业务描述处理结果”,在所有响应结构中都支持传入符合业务场景的 message

  • data:
    • 查询单条数据时直接返回对象结构,减少数据层级;
    • 查询列表数据时返回数组结构;
    • 创建或更新成功,返回修改后的数据;(也可以不返回数据直接返回空对象)
    • 删除成功时返回空对象
  • status:
    • error, 客服端出错,HTTP 状态响应码在400-599之间。如,传入错误参数,访问不存在的数据资源等
    • fail,服务端出错,HTTP 状态响应码在500-599之间。如,代码语法错误,空对象调用函数,连接数据库失败,undefined index等
    • success, HTTP 响应状态码为1XX、2XX和3XX,用来表示业务处理成功。
  • message: 描述执行的请求操作处理的结果;也可以支持国际化,根据实际业务需求来切换。
  • code: HTTP 响应状态码;可以根据实际业务需求,调整成业务操作码

使用

在需要进行 HTTP 响应的地方使用 \\App\\Traits\\Helpers\\App\\Http\\Response 中封装的响应方法进行调用。

通常使用是在 Controller 层中根据业务处理的结果进行响应,所以在 \\App\\Http\\Controllers 基类中已经引入了 Helpers trait,可以直接在 Controller 中进行如下调用:

// 操作成功情况
$this->response->success($data,$message);
$this->response->created($data,$message);
$this->response->accepted($message);
$this->response->noContent($message);

// 操作失败或异常情况
$this->response->fail($message);
$this->response->errorNotFound();
$this->response->errorBadRequest();
$this->response->errorForbidden();
$this->response->errorInternal();
$this->response->errorUnauthorized();
$this->response->errorMethodNotAllowed();
复制代码

操作成功时的响应结构

  • 返回单条数据
{
    "data": {
        "nickname": "Jiannei",
        "email": "longjian.huang@foxmail.com"
    },
    "status": "success",
    "code": 200,
    "message": "成功"
}
复制代码
  • 返回列表数据
{
    "data": [
        {
            "nickname": "Jiannei",
            "email": "longjian.huang@foxmail.com"
        },
        {
            "nickname": "Qian",
            "email": "1234567891@foxmail.com"
        },
        {
            "nickname": "Turbo",
            "email": "123456789@foxmail.com"
        }
        // ...
    ],
    "links": {
        "first": "http://lumen-api.test/users?page=1",
        "last": null,
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "path": "http://lumen-api.test/users",
        "per_page": 15,
        "to": 13
    },
    "status": "success",
    "code": 200,
    "message": "成功"
}
复制代码

操作失败时的响应结构

{
    "status": "fail",
    "code": 500,
    "message": "Service error",
    "data": {}
}
复制代码

异常捕获时的响应结构

整体格式与业务操作成功和业务操作失败时的一致,相比失败时,data 部分会增加额外的异常信息展示,方便项目开发阶段进行快速地问题定位。

  • 自定义实现了 ValidationException 的响应结构
{
    "status": "error",
    "code": 422,
    "message": "Validation error",
    "data": {
        "email": [
            "The email has already been taken."
        ],
        "password": [
            "The password field is required."
        ]
    }
}
复制代码
  • NotFoundException 异常捕获的响应结构

关闭 debug 时:

{
    "status": "error",
    "code": 404,
    "message": "Service error",
    "data": {
        "message": "No query results for model [App\\Models\\User] 19"
    }
}
复制代码

开启 debug 时:

{
    "status": "error",
    "code": 404,
    "message": "Service error",
    "data": {
        "message": "No query results for model [App\\Models\\User] 19",
        "exception": "Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException",
        "file": "/var/www/lumen-api-starter/vendor/laravel/lumen-framework/src/Exceptions/Handler.php",
        "line": 107,
        "trace": [
            {
                "file": "/var/www/lumen-api-starter/app/Exceptions/Handler.php",
                "line": 55,
                "function": "render",
                "class": "Laravel\\Lumen\\Exceptions\\Handler",
                "type": "->"
            },
            {
                "file": "/var/www/lumen-api-starter/vendor/laravel/lumen-framework/src/Routing/Pipeline.php",
                "line": 72,
                "function": "render",
                "class": "App\\Exceptions\\Handler",
                "type": "->"
            },
            {
                "file": "/var/www/lumen-api-starter/vendor/laravel/lumen-framework/src/Routing/Pipeline.php",
                "line": 50,
                "function": "handleException",
                "class": "Laravel\\Lumen\\Routing\\Pipeline",
                "type": "->"
            }
            // ...
        ]
    }
}
复制代码
  • 其他类型异常捕获时的响应结构
{
    "status": "fail",
    "code": 500,
    "message": "syntax error, unexpected '$user' (T_VARIABLE)",
    "data": {
        "message": "syntax error, unexpected '$user' (T_VARIABLE)",
        "exception": "ParseError",
        "file": "/var/www/lumen-api-starter/app/Http/Controllers/UsersController.php",
        "line": 34,
        "trace": [
            {
                "file": "/var/www/lumen-api-starter/vendor/composer/ClassLoader.php",
                "line": 322,
                "function": "Composer\\Autoload\\includeFile"
            },
            {
                "function": "loadClass",
                "class": "Composer\\Autoload\\ClassLoader",
                "type": "->"
            },
            {
                "function": "spl_autoload_call"
            }
           // ...
        ]
    }
}
复制代码

特别说明:使用 Postman 等 Api 测试工具的使用需要添加 X-Requested-With:XMLHttpRequest 或者 Accept:application/json header 信息来表明是 Api 请求,否则在异常捕获到后返回的可能不是预期的 JSON 格式响应。

丰富的日志模式支持

Repository & Service 模式架构

使用了 andersao/l5-repository 进行进行项目结构设计,补充添加了 Service 层。

职责说明

待补充。

规范

命名规范:待补充

使用规范:待补充

Packages

其他

依照惯例,如对您的日常工作有所帮助或启发,欢迎单击三连 star + fork + follow

如果有任何批评建议,通过邮箱(longjian.huang@foxmial.com)的方式(如果我每天坚持看邮件的话)可以联系到我。

总之,欢迎各路英雄好汉。

参考

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章