API 响应
现代 PHP 开发中,构建 API 已成为常见需求,无论是为 JavaScript 驱动的单页应用提供数据,还是作为独立产品。CodeIgniter 提供了若干 Trait,可配合任何控制器使用,以简化常用响应类型的处理,且无需记忆各响应类型对应的 HTTP 状态码。
响应示例
以下示例展示了控制器中的常见用法模式。
<?php
namespace App\Controllers;
use CodeIgniter\API\ResponseTrait;
use CodeIgniter\Controller;
class Users extends Controller
{
use ResponseTrait;
public function createUser()
{
$model = new UserModel();
$user = $model->save($this->request->getPost());
// Respond with 201 status code
return $this->respondCreated();
}
}
此示例返回 HTTP 状态码 201 及通用状态消息 "Created"。该 Trait 为最常见的用例提供了方法:
<?php
// Generic response method
$this->respond($data, 200);
// Generic failure response
$this->fail($errors, 400);
// Item created response
$this->respondCreated($data);
// Item successfully deleted
$this->respondDeleted($data);
// Command executed by no response required
$this->respondNoContent($message);
// Client isn't authorized
$this->failUnauthorized($description);
// Forbidden action
$this->failForbidden($description);
// Resource Not Found
$this->failNotFound($description);
// Data was not validated
$this->failValidationErrors($errors);
// Resource already exists
$this->failResourceExists($description);
// Resource previously deleted
$this->failResourceGone($description);
// Client made too many requests
$this->failTooManyRequests($description);
处理响应类型
调用这些方法传入数据时,系统将根据以下规则确定数据类型以格式化结果:
根据控制器的
$this->format值确定格式。 若该值为null,将尝试与客户端请求进行内容协商, 默认使用 app/Config/Format.php 中$supportedResponseFormats属性的第一个元素(默认为 JSON)。数据将按格式进行格式化。若非 JSON 格式且数据为字符串,将视为 HTML 返回给客户端。
备注
在 v4.5.0 之前,由于一个 Bug,若数据为字符串,即使格式为 JSON 也会被视为 HTML。
如需定义所使用的格式化程序,请编辑 app/Config/Format.php。$supportedResponseFormats 包含应用可自动格式化的 MIME 类型。系统默认支持 XML 和 JSON 响应格式:
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Format extends BaseConfig
{
public $supportedResponseFormats = [
'application/json',
'application/xml',
];
// ...
}
备注
自 v4.7.0 起,通过编辑 app/Config/Format.php 文件可修改默认 JSON 编码深度。$jsonEncodeDepth 值用于定义最大深度,默认值为 512。
进行 内容协商 时,通过该数组确定返回的响应类型。若客户端请求与支持的格式不匹配,则返回数组中的第一个格式。
接下来,需要定义用于格式化数据数组的类。必须是完全限定类名,且该类必须实现 CodeIgniter\Format\FormatterInterface。框架内置支持 JSON 和 XML 的格式化程序:
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Format extends BaseConfig
{
public $formatters = [
'application/json' => \CodeIgniter\Format\JSONFormatter::class,
'application/xml' => \CodeIgniter\Format\XMLFormatter::class,
];
// ...
}
因此,若请求在 Accept 标头中要求 JSON 格式的数据,传递给任何 respond* 或 fail* 方法的数据数组将由 CodeIgniter\Format\JSONFormatter 类格式化,生成的 JSON 数据将返回给客户端。
类参考
- setResponseFormat($format)
- 参数:
$format (
string) -- 要返回的响应类型,json或xml
用于定义响应中数组格式化的方式。若将
$format设为null,则通过内容协商自动确定格式。
<?php
return $this->setResponseFormat('json')->respond(['error' => false]);
- respond($data[, $statusCode = 200[, $message = '']])
- 参数:
$data (
mixed) -- 要返回给客户端的数据,字符串或数组。$statusCode (
int) -- 要返回的 HTTP 状态码,默认为 200$message (
string) -- 要返回的自定义“原因”消息。
Trait 中的其他方法均通过此方法向客户端返回响应。
$data参数可以是字符串或数组。默认情况下,字符串作为 HTML 返回,数组则经 json_encode 处理后作为 JSON 返回;除非通过 内容协商 确定了其他返回格式。若传入
$message字符串,则会替换响应状态中标准的 IANA 原因短语。但并非所有客户端都支持自定义代码,部分客户端仍会使用与状态码对应的 IANA 标准说明。备注
由于此方法会设置当前 Response 实例的状态码和正文,因此应始终作为脚本执行过程中的最后一个方法调用。
- fail($messages[, int $status = 400[, string $code = null[, string $message = '']]])
- 参数:
$messages (
mixed) -- 包含遇到错误消息的字符串或字符串数组。$status (
int) -- 要返回的 HTTP 状态码,默认为 400。$code (
string) -- 自定义 API 专用错误码。$message (
string) -- 要返回的自定义“原因”消息。
- 返回:
以客户端首选格式返回的 multi-part 响应。
表示失败响应的通用方法,所有其他 "fail" 方法均使用此方法。
$messages元素可为字符串或字符串数组。$status参数为应返回的 HTTP 状态码。由于许多 API 更适合使用自定义错误码,可在第三个参数中传入自定义错误码。若未提供值,将与
$status相同。若传入
$message字符串,将替代响应状态的标准 IANA 原因码。但并非所有客户端都支持自定义原因码,部分客户端仍会使用与状态码匹配的 IANA 标准。响应是一个包含三个元素的数组:
status、code和messages。status元素包含错误状态码。code元素包含 API 专用的自定义错误代码。messages元素包含错误消息数组。
根据错误消息的数量,响应示例如下:
<?php // Example response with a single error message $response = [ 'status' => 400, 'code' => '321', 'messages' => [ 'error' => 'An error occurred', ], ]; // Example response with multiple error messages per field $response = [ 'status' => 400, 'code' => '321a', 'messages' => [ 'foo' => 'Error message 1', 'bar' => 'Error message 2', ], ];
- respondCreated($data = null[, string $message = ''])
- 参数:
$data (
mixed) -- 要返回给客户端的数据,字符串或数组。$message (
string) -- 要返回的自定义“原因”消息。
- 返回:
Response 对象 send() 方法的返回值。
创建新资源时设置相应的状态码,通常为 201:
<?php $user = $userModel->insert($data); return $this->respondCreated($user);
- respondDeleted($data = null[, string $message = ''])
- 参数:
$data (
mixed) -- 要返回给客户端的数据,字符串或数组。$message (
string) -- 要返回的自定义“原因”消息。
- 返回:
Response 对象 send() 方法的返回值。
API 调用成功删除资源时设置相应的状态码,通常为 200。
<?php $user = $userModel->delete($id); return $this->respondDeleted(['id' => $id]);
- respondNoContent(string $message = 'No Content')
- 参数:
$message (
string) -- 要返回的自定义“原因”消息。
- 返回:
Response 对象 send() 方法的返回值。
服务器成功执行命令但无内容返回时,设置相应的状态码,通常为 204:
<?php sleep(1); return $this->respondNoContent();
- failUnauthorized(string $description = 'Unauthorized'[, string $code = null[, string $message = '']])
- 参数:
$description (
string) -- 向用户显示的错误消息。$code (
string) -- 自定义 API 专用错误码。$message (
string) -- 要返回的自定义“原因”消息。
- 返回:
Response 对象 send() 方法的返回值。
未经授权或授权错误时设置相应的状态码,状态码为 401。
<?php return $this->failUnauthorized('Invalid Auth token');
- failForbidden(string $description = 'Forbidden'[, string $code=null[, string $message = '']])
- 参数:
$description (
string) -- 向用户显示的错误消息。$code (
string) -- 自定义 API 专用错误码。$message (
string) -- 要返回的自定义“原因”消息。
- 返回:
Response 对象 send() 方法的返回值。
与
failUnauthorized()不同,当请求的 API 端点完全禁止访问时,应使用此方法。Unauthorized 即建议客户端更换凭据重试。Forbidden 则表示重试无效,不应再次尝试。状态码为 403。<?php return $this->failForbidden('Invalid API endpoint.');
- failNotFound(string $description = 'Not Found'[, string $code=null[, string $message = '']])
- 参数:
$description (
string) -- 向用户显示的错误消息。$code (
string) -- 自定义 API 专用错误码。$message (
string) -- 要返回的自定义“原因”消息。
- 返回:
Response 对象 send() 方法的返回值。
找不到请求的资源时设置相应的状态码,状态码为 404。
<?php return $this->failNotFound('User 13 cannot be found.');
- failValidationErrors($errors[, string $code=null[, string $message = '']])
- 参数:
$errors (
mixed) -- 向用户显示的错误消息或消息数组。$code (
string) -- 自定义 API 专用错误码。$message (
string) -- 要返回的自定义“原因”消息。
- 返回:
Response 对象 send() 方法的返回值。
客户端发送的数据未通过验证规则时设置相应的状态码,通常为 400。
<?php return $this->failValidationErrors($validation->getErrors());
- failResourceExists(string $description = 'Conflict'[, string $code=null[, string $message = '']])
- 参数:
$description (
string) -- 向用户显示的错误消息。$code (
string) -- 自定义 API 专用错误码。$message (
string) -- 要返回的自定义“原因”消息。
- 返回:
Response 对象 send() 方法的返回值。
客户端尝试创建的资源已存在时,设置相应的状态码,通常为 409。
<?php return $this->failResourceExists('A user already exists with that email.');
- failResourceGone(string $description = 'Gone'[, string $code=null[, string $message = '']])
- 参数:
$description (
string) -- 向用户显示的错误消息。$code (
string) -- 自定义 API 专用错误码。$message (
string) -- 要返回的自定义“原因”消息。
- 返回:
Response 对象 send() 方法的返回值。
请求的资源此前已被删除且不再可用时,设置相应的状态码。状态码通常为 410。
<?php return $this->failResourceGone('That user has been previously deleted.');
- failTooManyRequests(string $description = 'Too Many Requests'[, string $code=null[, string $message = '']])
- 参数:
$description (
string) -- 向用户显示的错误消息。$code (
string) -- 自定义 API 专用错误码。$message (
string) -- 要返回的自定义“原因”消息。
- 返回:
Response 对象 send() 方法的返回值。
客户端调用 API 端点次数过多时设置相应的状态码。通常源于流量控制或频率限制。状态码通常为 400。
<?php return $this->failTooManyRequests('You must wait 15 seconds before making another request.');
- failServerError(string $description = 'Internal Server Error'[, string $code = null[, string $message = '']])
- 参数:
$description (
string) -- 向用户显示的错误消息。$code (
string) -- 自定义 API 专用错误码。$message (
string) -- 要返回的自定义“原因”消息。
- 返回:
Response 对象 send() 方法的返回值。
服务器发生错误时设置相应的状态码。
<?php return $this->failServerError('Server error.');
分页响应
从 API 端点返回分页结果时,可使用 paginate() 方法同时返回结果与分页信息。这有助于保持 API 响应的一致性,同时提供客户端进行分页所需的全部信息。
使用示例
<?php
use App\Controllers\BaseController;
use App\Models\UserModel;
use CodeIgniter\API\ResponseTrait;
class UserController extends BaseController
{
use ResponseTrait;
public function index()
{
$model = model(UserModel::class)
->where('active', 1);
return $this->paginate($model, 20);
}
}
典型响应示例如下:
{
"data": [
{
"id": 1,
"username": "admin",
"email": "admin@example.com"
},
{
"id": 2,
"username": "user",
"email": "user@example.com"
}
],
"meta": {
"page": 1,
"perPage": 20,
"total": 2,
"totalPages": 1
},
"links": {
"self": "http://example.com/users?page=1",
"first": "http://example.com/users?page=1",
"last": "http://example.com/users?page=1",
"next": null,
"previous": null
}
}
paginate() 方法始终将结果封装在 data 元素中,并包含 meta 与 links 元素以辅助客户端翻页。若无结果,data 元素将为空数组,meta 与 links 元素依然存在,但其值将反映无结果状态。
除了模型,也可传入 Builder 实例,只需确保 Builder 已正确配置表名以及必要的 Join 或 Where 子句。
<?php
use App\Controllers\BaseController;
use CodeIgniter\API\ResponseTrait;
class UserController extends BaseController
{
use ResponseTrait;
public function index()
{
$builder = db_connect()
->table('users')
->where('active', 1);
return $this->paginate(resource: $builder, perPage: 20);
}
}
类参考
- paginate(Model|BaseBuilder $resource, int $perPage = 20, ?string $transformWith = null)
- 参数:
$resource (
Model|BaseBuilder) -- 要分页的资源,可为模型或 Builder 实例。$perPage (
int) -- 每页返回的条目数。$transformWith (
string|null) -- 可选的转换器类名,用于转换结果。
根据给定资源生成分页响应。资源可为模型或 Builder 实例。该方法会自动从请求的查询参数中确定当前页码。响应将包含分页数据、分页状态元数据以及页面导航链接。
如果提供包含转换器类名的
$transformWith参数,分页结果中的每个条目在返回前都将使用该转换器进行转换。这有助于精确控制 API 响应的结构与内容。有关创建和使用转换器的更多信息,请参阅 API 转换器。带有转换器的示例:
<?php use App\Controllers\BaseController; use App\Models\UserModel; use App\Transformers\UserTransformer; use CodeIgniter\API\ResponseTrait; class UserController extends BaseController { use ResponseTrait; public function index() { $model = model(UserModel::class); return $this->paginate(resource: $model, perPage: 20, transformWith: UserTransformer::class); } }