欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

Laravel API 系列教程(一): 基于 Laravel 5.5 构建 & 测试 RESTful API 有大用

Laravel API 系列教程(一): 基于 Laravel 5.5 构建 & 测试 RESTful API

随着移动开发和 JavaScript 框架的日益流行,使用 RESTful API 在数据层和客户端之间构建交互接口逐渐成为最佳选择。在本系列教程中,学院君将会带领大家基于 Laravel 5.5 来构建并测试带认证功能的 RESTful API。 

RESTful API

开始之前,我们先要了解什么是 RESTful API。REST 是 REpresentational State Transfer 的缩写,表示一种应用之间网络通信的架构风格,依赖于无状态的协议(通常是HTTP)进行交互。

通过 HTTP 动词表示操作

在 RESTful API 中,我们使用 HTTP 动词表示操作,而端点是操作的资源,HTTP 动词的语义如下:

  • GET:获取资源

  • POST:创建资源

  • PUT:更新资源

  • DELETE:删除资源

更新操作:PUT vs. POST

关于 RESTful API 有很多争议,比如更新资源使用 POSTPATCH 还是 PUT 哪一个更好,或者创建资源是否最好用 PUT 等。在本教程中,我们使用 PUT 进行更新操作,因为基于 HTTP RFC 标准,PUT 的含义是在指定位置上创建/更新资源;使用 PUT 的另一个原因是幂等,这意味着不管你发送一次、两次还是上千次请求,操作结果一致。

资源

资源指的是操作的对象,在我们的例子中就是文章(Articles)和用户(Users),它们各自的端点是:

  • /articles

  • /users

在我们的教程中,资源和数据模型一一对应,但这并不是强制性的要求,一个资源可以表示多个数据模型(或者不代表数据库中的任何模型),你可以根据自己应用的需求来决定如何构建资源和模型的映射关系。

关于一致性的注意项

使用 REST 的最大好处是可以更容易消费和开发 API,一些端点非常直截了当,这样相较于类似 GET /get_article?id_article=12 这样的端点 RESTful API 更容易使用和维护。 不过,在某些案例中映射到 Create/Retrieve/Update/Delete 可能会很困难,需要牢记的是 URL 中不要包含任何动词而且资源并不一定非得是数据表的某一行数据。另一个需要记住的是不必为每个资源实现所有操作。

 

设置一个新的 Laravel 项目

创建新应用

我们通过 Composer 来安装这个新项目:

安装完成后,如果使用 Valet 作为开发环境的话就可以直接在浏览器中通过 http://apidemo.test 访问了,如果使用 Laradock 或 Homestead 作为开发环境的话,还需要配置域名绑定:

然后还要配置 Nginx 的配置文件,以 Laradock 为例,就是在 laradock/nginx/sites 目录下新建一个 apidemo.conf 配置文件,编辑其内容如下:

之后重新启动 Nginx:

就可以在浏览器中通过 http://apidemo.test 访问应用了: 

迁移和模型

在编写第一个迁移之前,需要将 .env 文件中的环境变量调整为开发环境数据库配置值(以 Laradock 为例):

接下来就可以开始创建我们的第一个 Article 模型及其对应迁移文件了,我们在项目根目录运行如下 Artisan 命令一步到位:

-m 是 --migration 的缩写,告知 Artisan 在创建模型同时创建与之对应的迁移文件(我使用的是 Laradock 作为开发环境):  当然,还需要编辑默认生成的迁移文件:

然后我们运行如下命令创建对应数据表:

 现在我们回到 Article 模型类添加如下属性到 $fillable 字段以便可以在 Article::create 和 Article::update 方法中可以使用它们:

数据库填充

Laravel 通过 Faker 库可以快速为我们生成格式正确的测试数据:

生成的填充器类位于 /database/seeds 目录下,我们编辑填充器类如下:

然后运行填充命令:

重复上述过程创建一个用户填充器:

编辑 DatabaseSeeder 类:

然后运行 php artisan db:seed 就可以执行所有填充器填充数据。

路由和控制器

注册路由

有了数据之后,接下来我们来为应用创建基本接口:创建、获取列表、获取单条记录、更新以及删除。在 routes/api.php 中,注册路由如下:

在 api.php 中定义的路由在访问时需要加上 /api/ 前缀,并且 API 限流中间件会自动应用到所有路由上: 

创建控制器

定义好路由之后,接下来我们来创建控制器并将业务逻辑迁移过去:

然后编辑控制器如下:

调整 routes/api.php 文件中的 articles 相关路由:

还可以通过隐式路由模型绑定来改写路由定义:

相应的,需要调整控制器代码:

访问指定路由与之前返回结果一样: 

关于 HTTP 状态码的注意项

我们还添加了 response()->json() 调用到端点,这可以让我们在显示返回 JSON 数据的同时发送可以被客户端解析的 HTTP 状态码,最常用的状态码如下:

  • 200:OK,标准的响应成功状态码

  • 201:Object created,用于 store 操作

  • 204:No content,操作执行成功,但是没有返回任何内容

  • 206:Partial content,返回部分资源时使用

  • 400:Bad request,请求验证失败

  • 401:Unauthorized,用户需要认证

  • 403:Forbidden,用户认证通过但是没有权限执行该操作

  • 404:Not found,请求资源不存在

  • 500:Internal server error,通常我们并不会显示返回这个状态码,除非程序异常中断

  • 503:Service unavailable,一般也不会显示返回,通常用于排查问题用

 

发送 404 响应

如果你试图获取不存在的资源,会返回 404 页面:  如果想要将其改造成返回 JSON 响应,可以编辑异常处理器 app/Exceptions/Handler.php 的 render 方法:

再次访问不存在的资源,返回结果如下: 

认证

新增 api_token 字段

在 Laravel 中实现 API 认证有多种方式(例如 Passport),但是本教程会使用一个非常简化的方式。 开始之前,首先添加 api_token 到 users 表:

然后编写这个迁移文件:

最后执行迁移命令作用于数据表:

创建注册接口

我们使用 RegisterController 来根据注册请求返回正确的响应。尽管 Laravel 开箱提供了认证功能,但是我们还是需要对其进行调整以便返回我们想要的响应数据。该控制器使用 RegistersUsers 来实现注册,实现逻辑如下:

我们只需要在 RegisterController 中实现 registered 方法即可。该方法接收 $request 和 $user 参数:

在 routes/api.php 中注册路由如下:

在上面的示例代码中,我们调用了 User 模型上的生成令牌方法,该方法现在不存在,需要手动添加:

至此,注册接口编写完成,用户现在可以通过注册接口进行注册了,感谢 Laravel 开箱提供的认证字段验证功能,如果你需要调整验证规则的话可以到 RegisterController 中查看 validator 方法。 下面我们来简单测试下注册接口:

创建登录接口

和注册接口一样,可以编辑 LoginController 控制器来支持 API 认证。为此,我们需要在 LoginController 覆盖 AuthenticatesUsers trait 提供的 login 方法:

然后在 routes/api.php 中注册登录路由:

现在,基于我们上面注册的新用户,我们来测试下登录接口:

登录成功返回结果:  后面就可以拿着这个 api_token 作为令牌来请求需要认证的资源了。使用我们现有的策略,请求认证资源时,如果没有 token 或 token 错误,用户将会接收到未认证响应(401)。

创建退出接口

为了形成完整闭环,下面我们来编写退出登录接口,实现思路是用户发起退出登录请求时,我们将其对应的 token 字段值从数据库移除。 首先,在 routes/api.php 中注册路由:

然后在 Auth\LoginController.php 中编写 logout 方法:

使用该策略,一旦退出,用户的所有令牌都会失效,访问需要认证的接口都会拒绝访问(通过中间件实现),这需要和前端配合来避免用户在没有访问任何内容的权限下保持登录状态。

使用中间件限制访问

api_token 创建之后,我们就可以在路由文件中应用认证中间件了:

我们可以使用 $request->user() 或 Auth 门面访问当前用户:

接下来,我们将之前定义的文章相关路由进行分组:

这样就不需要为每个路由设置中间件,现在看来虽然节省不了多少时间,但随着应用体量的增长,这样做的好处是保持路由的DRY(Don't Repeat Yourself)。 再访问文章接口就需要认证了: 

测试接口

初始化设置

Laravel 开箱集成了 PHPUnit 进行测试,并且在项目根目录下为我们配置好了 phpunit.xml。本教程中,我们使用内置的测试方法来测试上面编写的 API。 开始之前,我们需要做一些小调整以便使用内存级的 SQLite 数据库进行数据存储。这样做的好处是可以让测试更快运行,但缺点是某些迁移命令可能不能正常运行,我的建议是当你遇到运行迁移命令出错或者更倾向于更加健壮的测试而不是高性能时不要使用 SQLite。 我们还会在每个测试之前运行迁移,这样就可以为每次测试构建数据库然后销毁掉,从而避免不同组测试间的相互干扰。 在 config/database.php 文件中,设置 sqlite 配置项中的 database 字段值为 :memory:

然后在 phpunit.xml 中通过新增 DB_CONNECTION 环境变量来启用 SQLite:

基本配置已经完成,生下来要做的就是配置 TestCase 在每次测试前运行迁移并填充数据库。为此,我们需要添加 DatabaseMigrations trait 然后在 setUp() 方法中添加 Artisan 调用:

最后一件事就是添加测试命令到 composer.json

我们通过这个命令来运行测试:

如果运行过程中抛出异常:

这是因为没有安装 doctrine/dbal 扩展包,使用 Composer 安装即可:

下面是运行结果: 

为测试设置模型工厂

模型工厂可以让我们快速生成测试数据,Laravel 开箱自带了 User 模型工厂,下面我们为 Article 类添加工厂:

然后编辑 ArticleFactory 类:

编写测试用例

我们可以使用 Laravel 的断言方法对请求和响应进行测试。下面我们来创建第一个测试用例 —— 登录测试:

编写 LoginTest 代码如下:
然后编写注册测试用例:
编写 RegisterTest 代码如下:
最后,编写退出测试用例:
编辑 LogoutTest 代码如下:
注:在测试期间,Laravel 应用并不会在发起新请求时再次初始化,所以会在请求之间保存当前用户到 TokenGuard 实例,也因此我们不得不将退出测试一分为二,以避免受之前缓存用户的影响。
测试文章 API 接口的代码也很简单:
编写 ArticleTest 代码如下:
要运行测试的话的随时运行 composer test 即可。 至此,我们已经完成了 API 接口的编写和测试,下一篇我们会基于 JWT 对 API 进行认证同时整合进 Vue SPA 做一个更偏向实战的教程,敬请期待。

上一篇: 编写 JSON API —— 基于资源控制器和 API 资源类快速构建 API 接口

下一篇: Laravel API 系列教程(二): 结合 Laravel 5.5 和 Vue SPA 基于 jwt-auth 实现 API 认证





来自  https://xueyuanjun.com/post/9153

普通分类: