xp-forge / rest-client
REST 客户端
v5.6.0
2024-03-24 13:23 UTC
Requires
- php: >=7.0.0
- xp-forge/compression: ^1.0
- xp-forge/json: ^5.0 | ^4.0 | ^3.1
- xp-forge/marshalling: ^2.0 | ^1.0
- xp-forge/uri: ^2.0 | ^1.3
- xp-framework/core: ^12.0 | ^11.0 | ^10.0
- xp-framework/http: ^10.0 | ^9.1
- xp-framework/logging: ^11.0 | ^10.0 | ^9.0 | ^8.0 | ^7.0
- xp-framework/tokenize: ^9.0 | ^8.0
Requires (Dev)
- xp-framework/test: ^2.0 | ^1.0
- dev-master
- v5.6.0
- v5.5.0
- v5.4.0
- v5.3.0
- v5.2.0
- v5.1.1
- v5.1.0
- v5.0.2
- v5.0.1
- v5.0.0
- v4.0.0
- v3.2.0
- v3.1.0
- v3.0.0
- v2.3.0
- v2.2.1
- v2.2.0
- v2.1.0
- v2.0.2
- v2.0.1
- v2.0.0
- v1.0.3
- v1.0.2
- v1.0.1
- v1.0.0
- v0.8.0
- v0.7.3
- v0.7.2
- v0.7.1
- v0.7.0
- v0.6.0
- v0.5.1
- v0.5.0
- v0.4.1
- v0.4.0
- v0.3.0
- v0.2.0
- v0.1.0
- dev-refactor/transfer
- dev-feature/timeout
- dev-feature/links
This package is auto-updated.
Last update: 2024-08-24 14:34:09 UTC
README
REST 客户端
用法
Endpoint
类作为此 API 的入口点。使用 REST 服务的端点 URL 创建它的一个新实例,然后调用其 resource()
方法来处理资源。
创建:post
use webservices\rest\Endpoint; $api= new Endpoint('https://api.example.com/'); $result= $api->resource('users')->post(['name' => 'Test'], 'application/json'); // Get location from created response, raising an UnexpectedStatus // exception for any statuscode outside of the range 200-299. $url= $result->location(); // Same as above, but handle 201 *AND* 200 status codes - see // https://stackoverflow.com/questions/1860645 $id= $result->match([ 200 => fn($r) => $r->value()['id'], 201 => fn($r) => (int)basename($r->location()) ]);
读取:get / head
use webservices\rest\Endpoint; $api= new Endpoint('https://api.example.com/'); // Test for existance with HEAD, raising UnexpectedStatus exceptions // for any status code other than 200 and 404. $exists= $api->resource('users/1549')->head()->match([ 200 => true, 404 => false ]); // Return user object, raising an UnexpectedStatus exception for any // statuscode outside of the range 200-299. $user= $api->resource('users/self')->get()->value(); // Same as above, but returns NULL for 404s instead of an exception $user= $api->resource('users/{0}', [$id])->get()->optional(); // Pass parameters $list= $api->resource('user')->get(['page' => 1, 'per_page' => 50])->value(); // Access pagination via `Link: <...>; rel="next"` header $resource= 'groups'; do { $result= $this->endpoint->resource($resource)->get(['per_page' => 200]); foreach ($result->value() as $group) { yield $group['id'] => $group; } } while ($resource= $result->link('next'));
更新:put / patch
use webservices\rest\Endpoint; $api= new Endpoint('https://api.example.com/'); $resource= $api->resource('users/self') ->sending('application/json') ->accepting('application/json') ; // Default content type and accept types set on resource used $updated= $resource->put(['name' => 'Tested', 'login' => $mail])->value(); // Resources can be reused! $updated= $resource->patch(['name' => 'Changed'])->value();
删除:delete
use webservices\rest\Endpoint; $api= new Endpoint('https://api.example.com/'); // Pass segments, map 204 to true, 404 to null, raise UnexpectedStatus // exception otherwise $api->resource('users/{id}', $user)->delete()->match([ 204 => true, 404 => null ]);
上传
多部分文件上传通过 upload()
方法启动,可以包含参数,并可以从任何输入流上传。
use io\File; use io\streams\MemoryInputStream; use webservices\rest\Endpoint; $stream= new MemoryInputStream('Hello'); $file= new File(...); $endpoint= new Endpoint($url); $result= $endpoint->resource('files')->upload() ->pass('tc', 'accepted') ->transfer('letter', $stream, 'letter.txt', 'text/plain') ->transfer('cv', $file->in(), $file->filename) ->finish() ;
反序列化
通过传递类型到 value()
方法,支持通过自动结果反序列化。
use com\example\api\types\User; $result= $api->resource('users/{0}', [$id])->get(); // If a type is passed, the result will be unmarshalled to an object $map= $result->value(); $object= $result->value(User::class); // Same for optional, but map and object will be NULL for 404s $map= $result->optional(); $object= $result->optional(User::class); // Works with any type from the XP typesystem, e.g. arrays of objects $list= $api->resource('users')->get()->value('org.example.User[]');
错误处理
对 Result
类的操作会引发 UnexpectedStatus
异常。以下是如何访问它们的状态和原因
use webservices\rest\UnexpectedStatus; use util\cmd\Console; // In unexpected cases try { $user= $api->resource('users/self')->get()->value(); } catch (UnexpectedStatus $e) { Console::writeLine('Unexpected ', $e->status(), ': ', $e->reason()); } // More graceful handling $result= $api->resource('users/self')->get(); if ($error= $result->error()) { Console::writeLine('Unexpected ', $result->status(), ': ', $error); } else { $user= $result->value(); }
身份验证
支持基本身份验证,通过在端点 URL 中嵌入凭据来实现。
use webservices\rest\Endpoint; $api= new Endpoint('https://user:pass@api.example.com/');
也可以在端点 URL 中嵌入 Bearer 令牌。
use webservices\rest\Endpoint; $api= new Endpoint('https://token@api.example.com/');
可以按照以下方式传递基于头的其他身份验证值
use webservices\rest\Endpoint; $api= (new Endpoint('https://api.example.com/'))->with(['X-API-Key' => $key]);
压缩
此库透明地处理压缩数据,发送一个包含 PHP 设置中支持的压缩算法的 Accept-Encoding 头(基于加载的扩展,如例如 zlib),并使用 Content-Encoding 响应头来确定选择哪个算法。
use webservices\rest\Endpoint; use io\streams\Compression; // Detect supported compression algorithms and set "Accept-Encoding" accordingly $endpoint= new Endpoint($api); // Send "Accept-Encoding: identity", indicating the server should not compress $endpoint= (new Endpoint($api))->compressing(Compression::$NONE); // Send "Accept-Encoding: gzip, br" $endpoint= (new Endpoint($api))->compressing(['gzip', 'br']); // Do not send an "Accept-Encoding" header, i.e. no preference is expressed $endpoint= (new Endpoint($api))->compressing(null);
可测试性
此库还包括方便编写对 REST API 进行调用的代码的单元测试的功能。通过使用 TestEndpoint 类并向其提供它应该响应的路由,可以轻松测试各种场景,而无需 HTTP 协议和 I/O 开销。
use webservices\rest\TestEndpoint; $endpoint= new TestEndpoint([ '/users/6100' => function($call) { return $call->respond(200, 'OK', ['Content-Type' => 'application/json'], '{ "id": 6100, "username": "binford" }'); }, 'POST /users' => function($call) { return $call->respond(201, 'Created', ['Location' => '/users/6100']); }, ]); $response= $endpoint->resource('/users/me')->get(); // Responds with HTTP status 200 and the above JSON payload