Laravel 第二章 Github 的 Restful HTTP API 设计分解 及 DingoAPI安装介绍 、 PostMan安装介绍

本文探讨RESTful API的设计原则,包括安全性、易读性和统一性,并通过DingoApi工具包演示如何在Laravel项目中实现RESTful风格的API。涵盖版本控制、资源定位、HTTP动词使用、状态码规范、数据格式、限流和文档编写等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是 RESTful?

RESTful 是一种软件设计风格,由 Roy Fielding 在他的 论文 中提出,全称为 Representational State Transfer,直译为表现层状态转移,或许可以解释为用 URL 定位资源,用 HTTP 动词描述操作,不用太纠结于定义,接下来我们会详细讨论。

RESTful 风格的接口,目前来看,实现的最好的就是 Github API,经常被效仿。接下来我们通过分析 Github API 来引出我们的 API 设计原则。

为什么选择 RESTful?

我认为一套接口应该尽量满足以下几个原则:

  • 安全可靠,高效,易扩展。
  • 简单明了,可读性强,没有歧义。
  • API 风格统一,调用规则,传入参数和返回数据有统一的标准。

我们当然可以根据自己的经验,或者参考知名公司的接口总结设计出一套满足要求的接口,但是每个人对接口的理解不同,设计出来的接口也会有所不同,接口的命名,请求参数的格式,响应的结果,错误响应的错误码,等等很多地方都会有不一样的实现。当你去寻求一种设计理念来帮助我们设计出满足要求的接口,一定会发现 RESTful。
RESTful 的设计理念基于 HTTP 协议,因为 Roy Fielding 就是 HTTP 协议(1.0 版和 1.1 版)的主要设计者。它是一种设计风格,没有规定我们一定如何实现,但是为我们提供了很好的设计理念。风格的统一,使得我们不需要过多的解释,就能让使用者明白该如何使用,同时也会有很多现成的工具来帮助我们实现 RESTful 风格的接口。

如何使用RESTful?

RESTful 设计原则

1. HTTPS

HTTPS 为接口的安全提供了保障,可以有效防止通信被窃听和篡改。而且现在部署 HTTPS 的成本也越来越低,你可以通过 cerbot 等工具,方便快速的制作免费的安全证书,所以生产环境,请务必使用 HTTPS。

另外注意,非 HTTPS 的 API 调用,不要重定向到 HTTPS,而要直接返回调用错误以禁止不安全的调用。

2. 域名

应当尽可能的将 API 与其主域名区分开,可以使用专用的域名,访问我们的 API,例如:

https://api.larabbs.com

或者可以放在主域名下,例如:

https://www.larabbs.com/api

3. 版本控制

随着业务的发展,需求的不断变化,API 的迭代是必然的,很可能当前版本正在使用,而我们就得开发甚至上线一个不兼容的新版本,为了让旧用户可以正常使用,为了保证开发的顺利进行,我们需要控制好 API 的版本。

通常情况下,有两种做法:

  • 将版本号直接加入 URL 中
    https://api.larabbs.com/v1
    https://api.larabbs.com/v2
  • 使用 HTTP 请求头的 Accept 字段进行区分    (推荐使用)
    https://api.larabbs.com/
        Accept: application/prs.larabbs.v1+json
        Accept: application/prs.larabbs.v2+json

    Github Api 虽然默认使用了第一种方法,但是其实是推荐并实现了第二种方法的,我们同样也尽量使用第二种方式。

4. 用 URL 定位资源

在 RESTful 的架构中,所有的一切都表示资源,每一个 URL 都代表着一种资源,资源应当是一个名词,而且大部分情况下是名词的复数,尽量不要在 URL 中出现动词。
先来看看 github 的 例子icon-default.png?t=M85Bhttps://developer.github.com/v3/issues/comments/GET:获取,罗列    POST:创建    PATCH:修改    PUT:设置    DELETE:删除

GET /issues                                      列出所有的 issue
GET /orgs/:org/issues                            列出某个项目的 issue
GET /repos/:owner/:repo/issues/:number           获取某个项目的某个 issue
POST /repos/:owner/:repo/issues                  为某个项目创建 issue
PATCH /repos/:owner/:repo/issues/:number         修改某个 issue
PUT /repos/:owner/:repo/issues/:number/lock      锁住某个 issue
DELETE /repos/:owner/:repo/issues/:number/lock   解锁某个 issue

例子中冒号开始的代表变量,例如 /repos/summerblue/larabbs/issues

在 github 的实现中,我们可以总结出:

  • 资源的设计可以嵌套,表明资源与资源之间的关系。
  • 大部分情况下我们访问的是某个资源集合,想得到单个资源可以通过资源的 id 或 number 等唯一标识获取。
  • 某些情况下,资源会是单数形式,例如某个项目某个 issue 的锁,每个 issue 只会有一把锁,所以它是单数。

错误的例子

POST https://api.larabbs.com/createTopic
GET https://api.larabbs.com/topic/show/1
POST https://api.larabbs.com/topics/1/comments/create
POST https://api.larabbs.com/topics/1/comments/100/delete

正确的例子

POST https://api.larabbs.com/topics
GET https://api.larabbs.com/topics/1
POST https://api.larabbs.com/topics/1/comments
DELETE https://api.larabbs.com/topics/1/comments/100

5. 用 HTTP 动词描述操作

HTTP 设计了很多动词,来表示不同的操作,RESTful 很好的利用的这一点,我们需要正确的使用 HTTP 动词,来表明我们要如何操作资源。
先来解释一个概念,幂等性,指一次和多次请求某一个资源应该具有同样的副作用,也就是一次访问与多次访问,对这个资源带来的变化是相同的。

常用的动词及幂等性

动词描述是否幂等
GET获取资源,单个或多个
POST创建资源
PUT更新资源,客户端提供完整的资源数据
PATCH更新资源,客户端提供部分的资源数据
DELETE删除资源

为什么 PUT 是幂等的而 PATCH 是非幂等的,因为 PUT 是根据客户端提供了完整的资源数据,客户端提交什么就替换为什么,而 PATCH 有可能是根据客户端提供的参数,动态的计算出某个值,例如每次请求后资源的某个参数减 1,所以多次调用,资源会有不同的变化。

另外需要注意的是,GET 请求对于资源来说是安全的,不允许通过 GET 请求改变(更新或创建)资源,但是真实使用中,为了方便统计类的数据,会有一些例外情况,例如帖子详情,记录访问次数,每调用一次,访问次数 +1;

6. 资源过滤

我们需要提供合理的参数供客户端过滤资源,例如

?state=closed: 不同状态的资源
?page=2&per_page=100:访问第几页数据,每页多少条。
?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。

7. 正确使用状态码

HTTP 提供了丰富的状态码供我们使用,正确的使用状态码可以让响应数据更具可读性。

  • 200 OK - 对成功的 GET、PUT、PATCH 或 DELETE 操作进行响应。也可以被用在不创建新资源的 POST 操作上
  • 201 Created - 对创建新资源的 POST 操作进行响应。应该带着指向新资源地址的 Location 头
  • 202 Accepted - 服务器接受了请求,但是还未处理,响应中应该包含相应的指示信息,告诉客户端该去哪里查询关于本次请求的信息
  • 204 No Content - 对不会返回响应体的成功请求进行响应(比如 DELETE 请求)
  • 304 Not Modified - HTTP 缓存 header 生效的时候用
  • 400 Bad Request - 请求异常,比如请求中的 body 无法解析
  • 401 Unauthorized - 没有进行认证或者认证非法
  • 403 Forbidden - 服务器已经理解请求,但是拒绝执行它
  • 404 Not Found - 请求一个不存在的资源
  • 405 Method Not Allowed - 所请求的 HTTP 方法不允许当前认证用户访问
  • 410 Gone - 表示当前请求的资源不再可用。当调用老版本 API 的时候很有用
  • 415 Unsupported Media Type - 如果请求中的内容类型是错误的
  • 422 Unprocessable Entity - 用来表示校验错误
  • 429 Too Many Requests - 由于请求频次达到上限而被拒绝访问

8. 数据响应格式

考虑到响应数据的可读性及通用性,默认使用 JSON 作为数据响应格式。如果客户端有需求使用其他的响应格式,例如 XML,需要在 Accept 头中指定需要的格式。

https://api.larabbs.com/
    Accept: application/prs.larabbs.v1+json
    Accept: application/prs.larabbs.v1+xml

对于错误数据,默认使用如下结构:

'message' => ':message',          // 错误的具体描述
'errors' => ':errors',            // 参数的具体错误描述,422 等状态提供
'code' => ':code',                // 自定义的异常码
'status_code' => ':status_code',  // http状态码
'debug' => ':debug',              // debug 信息,非生产环境提供

例如

{
    "message": "422 Unprocessable Entity",
    "errors": {
        "name": [
            "姓名 必须为字符串。"
        ]
    },
    "status_code": 422
}
{
    "message": "您无权访问该订单",
    "status_code": 403
}

9. 调用频率限制

为了防止服务器被攻击,减少服务器压力,需要对接口进行合适的限流控制,需要在响应头信息中加入合适的信息,告知客户端当前的限流情况

  • X-RateLimit-Limit :100 最大访问次数
  • X-RateLimit-Remaining :93 剩余的访问次数
  • X-RateLimit-Reset :1513784506 到该时间点,访问次数会重置为 X-RateLimit-Limit

超过限流次数后,需要返回 429 Too Many Requests 错误。

10. 编写文档

为了方便用户使用,我们需要提供清晰的文档,尽可能包括以下几点

  • 包括每个接口的请求参数,每个参数的类型限制,是否必填,可选的值等。
  • 响应结果的例子说明,包括响应结果中,每个参数的释义。
  • 对于某一类接口,需要有尽量详细的文字说明,比如针对一些特定场景,接口应该如何调用。

什么是 DingoApi?

dingo/api 是一个 Lumen 和 Laravel 都可用的 RestFul 工具包,帮助我们快速的开始构建 RestFul Api。我们的目的是教会大家如何快速的搭建并使用这个包,更多的功能,还需要你仔细阅读 DingoApi 的 文档 (Home · dingo/api Wiki · GitHub)来深入的学习和理解,这里(GitHub - liyu001989/dingo-api-wiki-zh: dingo/api 中文文档)有一份中英对照的翻译,或许能帮到你。

1. 安装

因为是 API 的课程,可以先创建一个 API 分支。

$ git checkout -b api

安装扩展包

$ composer require dingo/api:2.0.0-beta1

报错:

[Composer\Downloader\TransportException]                                                                                        

  The "https://packagist.phpcomposer.com/p/provider-2019-01%241083636756831bc6ca0a7b15a464cb6375f4a25e56edf670c6c3e3ad02f33000.j  

  son" file could not be downloaded (HTTP/1.1 404 Not Found)    

 解决办法:composer config -g repo.packagist composer https://packagist.laravel-china.org。更换镜像源。

没看懂,继续查找

执行composer config repo.packagist composer https://packagist.phpcomposer.com

将会在Code文件夹中larabbs/composer.json的末尾自动添加镜像的配置信息(你也可以自己手工添加):
"repositories": {
    "packagist": {
        "type": "composer",
        "url": "https://packagist.phpcomposer.com"
    }
}

可以把composer.json中修改一下

"packagist": {
  "type": "composer",
  "url": "https://packagist.phpcomposer.com"
}
修改成

"packagist": {
  "type": "composer",
  "url": "https://packagist.laravel-china.org"  //此处为更改成功的关键,将镜像地址更改,之前的地址下载资源有问题
}

下方要求添加两条语句,在此处直接添加

"config": {
        "preferred-install": "dist",
        "sort-packages": true,
        "optimize-autoloader": true
    },
    "minimum-stability" : "dev",  -->需要添加
    "prefer-stable" : true  -->需要添加

再次在 ~/code/larabbs $ composer require dingo/api  开始下载  当出现Package manifest generated successfully时,下载完成

dingo/api 已经发布了正式版本,目前最新版本为 2.2.3,但是存在一个较为严重的 Bug:https://github.com/dingo/api/issues/1645 ,在 Bug 修复之前还是会使用指定的版本。

发现报错了:

Your requirements could not be resolved to an installable set of packages.

dingo 的文档中有说明,现在这个包还处在开发阶段,没有一个稳定的 release 版本,dingo/api 依赖的 dingo/blueprint 与 phpunit 都依赖了 phpdocumentor/reflection-docblock 但是依赖的版本不同,导致出现了冲突。但是我们发现 dingo/blueprint 的开发版本 dev-master 解决了冲突,可以正常安装,所以我们修改一下 composer.json

composer.json

.
.
.
    "config": {
        "preferred-install": "dist",
        "sort-packages": true,
        "optimize-autoloader": true
    },
    "minimum-stability" : "dev",
    "prefer-stable" : true
}

增加了两句:

  • "minimum-stability" : "dev" —— 设定的最低稳定性的版本为 dev 也就是可以依赖开发版本的扩展包;
  • "prefer-stable" : true —— Composer 优先使用更稳定的包版本。

我们设定项目可以依赖开发版本扩展包,但是当依赖有稳定版本可以安装的时候,优先安装稳定版。

再次执行命令安装:

Package manifest generated successfully.  看到 dingo/api 已经成功安装了。

2. 配置

先将 dingo 的配置文件 publish 出来

$ php artisan vendor:publish

执行成功后,我们会在 config 目录先看到 api.php 文件,打开文件我们可以看到所有的配置都是可以再 env 中修改的,下面我们主要讲解一下我们需要用到的配置

  • API_STANDARDS_TREE 和 API_SUBTYPE

    上一节我们已经讨论了 API 版本的重要性,推荐的做法是使用 Accept 头来指定我们需要访问的 API 版本。API_STANDARDS_TREE 和 API_SUBTYPE 这两个配置就和版本控制有关

    Accept: application/<API_STANDARDS_TREE>.<API_SUBTYPE>.v1+json

    API_STANDARDS_TREE 有是三个值可选

    • x 本地开发的或私有环境的
    • prs 未对外发布的,提供给公司 app,单页应用,桌面应用等
    • vnd 对外发布的,开放给所有用户

    对于我们的项目,暂时可以选择 prs

    API_STANDARDS_TREE=prs

    API_SUBTYPE 一般情况下是我们项目的简称,我们的项目叫 larabbs

    API_SUBTYPE=larabbs

    所以我们可以通过如下方式来访问不同版本的 API

    访问 v1 版本
    Accept: application/prs.larabbs.v1+json
    访问 v2 版本
    Accept: application/prs.larabbs.v2+json
  • API_PREFIX 和 API_DOMAIN
    对于一个项目,通过前缀或者子域名的方式来区分开 API 与 Web 等页面访问地址是十分有必要的。假如正式上线的项目地址为 www.larabbs.com,我们可以为 API 添加一个前缀

    API_PREFIX=api

    通过 www.larabbs.com/api 来访问 API。
    或者有可能单独配置一个子域名 api.larabbs.com

    API_DOMAIN=api.larabbs.com

    通过 api.larabbs.com 来访问 API。

    特别要注意的是:前缀和子域名,两者有且只有一个。本教程选择 API_PREFIX 的方式。

  • API_VERSION
    默认的 API 版本,当我们没有传 Accept 头的时候,默认访问该版本的 API。一般情况下配置 v1 即可。
  • API_STRICT
    是否开启严格模式,如果开启,则必须使用 Accept 头才可以访问 API,也就是说直接通过浏览器,访问某个 GET 调用的接口,如 https://api.larabbs.com/users,将会报错。必须使用 Postman 之类的调试工具,设置 Accept 后才可访问。可以根据需求开启,默认情况下为 false。
  • API_DEBUG
    测试环境,打开 debug,方便我们看到错误信息,定位错误。
    最后我们的配置如下
    .env
    .
    .
    .
    API_STANDARDS_TREE=prs
    API_SUBTYPE=larabbs
    API_PREFIX=api
    API_VERSION=v1
    API_DEBUG=true

注意 .env 文件是不会提交到版本库中的,所以可以将以下代码复制到 .env.example 中,提交到版本库,方便其他环境部署。
.env.example

.
.
.
# dingo config
API_STANDARDS_TREE=
API_SUBTYPE=
API_PREFIX=
API_VERSION=
API_DEBUG=

3. 版本控制

最后将修改的文件加入到版本控制中。

$ git add -A
$ git commit -m "add dingo"

1. 什么是 PostMan?

PostMan 是一款跨平台,方便我们调试 API 的工具,你可以在 PostMan 官网()Postman 下载,或者使用 百度网盘下载(postman客户端_免费高速下载|百度网盘-分享无限制)。

打开 PostMan 界面如上图所示,大体可以分为四个区域,左侧接口集合类似文件夹的功能,我们可以把我们的接口保存在这里,右侧上中下分别是请求地址请求参数请求结果

随便找个接口调用一下,这个是国家气象局提供的 天气预报接口,将其填入『请求地址』处:

可以在左侧的区域,保存接口,我们新建一个 Larabbs 目录。

在左侧我们看到了新建的文件夹 Larabbs,然后保存接口。

可以给接口起个名字,填写响应的描述。

我们可以将已经调试好的接口保存下来,方便下次调试,PostMan 也为我们提供了导出导入接口的功能,方便分享接口给他人,当然 PostMan 也为付费用户提供了更多方便的功能,大家有需要的可以取官网了解,目前免费版的功能已经满足我们的需求。

2. 编写调试接口

已经安装好了 DingoApi,接下来写两个路由,尝试一下 PostMan。Laravel 5.5 已经为我们准备好了 api 的路由文件,routes/api.php。打开这个文件,可以看到 Laravel 为我们写好的例子。

<?php

use Illuminate\Http\Request;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::middleware('auth:api')->get('/user', function (Request $request) {
    return $request->user();
});

由于我们使用的是 DingoApi 的路由,所以将文件替换为如下内容

<?php

use Illuminate\Http\Request;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

$api = app('Dingo\Api\Routing\Router');//路由需要使用 Dingo\Api\Routing\Router 注册

$api->version('v1', function($api) {//version方法用于版本控制  参数1:版本名称,version是不同版本的路由
    $api->get('version', function() {
        return response('this is version v1');
    });
});

$api->version('v2', function($api) {
    $api->get('version', function() {
        return response('this is version v2');
    });
});

路由需要使用 Dingo\Api\Routing\Router 注册,写法同 Laravel 的路由,大家应该比较熟悉。DingoApi 提供了 version 方法,用来进行版本控制,第一个参数是版本名称,version 中的就是不用版本的路由。我们在 v1 和 v2 两个版本中,都注册了 verison 路由,但是响应不同,现在通过 PostMan 来试试。
还记得我们配置的是 API_PREFIX=api,所以需要 http://larabbs.test/api/version 来访问。

我们得到了 v1 版本的结果,this is version v1,因为配置了默认的版本是 v1 API_VERSION=v1。但是下面却多出来了一些 html,这其实是 Larabbs 安装的 laravel-debugbar,做接口相关的开发,不涉及网页,所以我们现在来关闭它。
打开 config/debugbar.php,可以看到一行配置 enabled

'enabled' => env('APP_DEBUG', false),

该配置控制 debugbar 的开启和关闭,但是它现在是随着 APP_DEBUG 的改变而改变的,我们可以把代码修改为

将 
'enabled' => env('APP_DEBUG', false),
更改为
'enabled' => env('DEBUGBAR_ENABLE', false),

这样我们本地测试环境 APP_DEBUG 依然可以是 true,同时也可以关闭 laravel-debugbar。默认 laravel-debugbar 是关闭的,我们再次通过 PostMan 访问该接口。

一切正常了,记得当我们调试网页,需要用到 laravel-debugbar 的时候,在 .env 中增加 DEBUGBAR_ENABLE=true即可。

下面我们在Headers中增加KEY:Accept  VALUE:application/prs.larabbs.v2+json 来访问 v2 版本的 version。

此时Postman出现错误:Unable to round-trip http request to upstream: lookup larabbs.test on 127.0.0.1:53: no such host

当使用网页http://larabbs.test/api/version 可以访问到this is version v1

解决方案:将蓝灯关闭即可,蓝灯影响

成功输出:this is version v2

提示:由于路由被 DingoApi 接管了,如果将来部署上线后你需要缓存路由,可以使用 php artisan api:cache代替 php artisan route:cache ,本地测试请不要执行这个命令

3. PostMan 的环境变量功能

PostMan 为我们提供了环境变量的功能,通过切换不同的值,可以使用不同的环境,比如 host 我们就可以做成变量,这样当我们某一天切换了本地调试的域名,比如由 larabbs.app 切换为 larabbs.test 时,不用去每个接口中修改,只需要修改变量即可。

在右上角设置图标——Manager Environment——Add——Add Environment:填入环境名称——Key:用于替换域名所起的名称——Value:被替换的域名名称

如:Key:host    Value:larabbs.test     在使用时,https://{host}/api/version

比如上面,我们增加了一个环境变量 host,然后我们选择对应的环境,将域名替换为 {{host}},PostMan url 中,使用双括号表示变量。同样能访问得到正确的结果。

4. 代码版本控制

最后,我们将测试的路由代码恢复:

$ git checkout routes/api.php

然后将 config/debugbar.php 提交:

$ git add -A
$ git commit -m "fix laravel-debugbar"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值