PHPackages                             xp-forge/rest-client - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. xp-forge/rest-client

ActiveLibrary[HTTP &amp; Networking](/categories/http)

xp-forge/rest-client
====================

REST Client

v6.2.0(2mo ago)048.8k—8.3%1[2 PRs](https://github.com/xp-forge/rest-client/pulls)3BSD-3-ClausePHPPHP &gt;=7.4.0CI passing

Since Aug 30Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/xp-forge/rest-client)[ Packagist](https://packagist.org/packages/xp-forge/rest-client)[ Docs](http://xp-framework.net/)[ RSS](/packages/xp-forge-rest-client/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (9)Versions (52)Used By (3)

Rest Client
===========

[](#rest-client)

[![Build status on GitHub](https://github.com/xp-forge/rest-client/workflows/Tests/badge.svg)](https://github.com/xp-forge/rest-client/actions)[![XP Framework Module](https://raw.githubusercontent.com/xp-framework/web/master/static/xp-framework-badge.png)](https://github.com/xp-framework/core)[![BSD Licence](https://raw.githubusercontent.com/xp-framework/web/master/static/licence-bsd.png)](https://github.com/xp-framework/core/blob/master/LICENCE.md)[![Requires PHP 7.4+](https://raw.githubusercontent.com/xp-framework/web/master/static/php-7_4plus.svg)](http://php.net/)[![Supports PHP 8.0+](https://raw.githubusercontent.com/xp-framework/web/master/static/php-8_0plus.svg)](http://php.net/)[![Latest Stable Version](https://camo.githubusercontent.com/7eca9ac33140e1d46f677b0bdff41f973dce778aac3a4ad43856b1fed5911178/68747470733a2f2f706f7365722e707567782e6f72672f78702d666f7267652f726573742d636c69656e742f76657273696f6e2e737667)](https://packagist.org/packages/xp-forge/rest-client)

REST client

Usage
-----

[](#usage)

The `Endpoint` class serves as the entry point to this API. Create a new instance of it with the REST service's endpoint URL and then invoke its `resource()` method to work with the resources.

### Creating: post

[](#creating-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())
]);
```

### Reading: get / head

[](#reading-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'));
```

### Updating: put / patch

[](#updating-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();
```

### Deleting: delete

[](#deleting-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
]);
```

### Uploads

[](#uploads)

Multipart file uploads are initiated by the `upload()` method, may include parameters and can upload from any input stream.

```
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()

;
```

### Deserialization

[](#deserialization)

Automatic result deserialization is supported by passing a type to the `value()` method.

```
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[]');
```

### Error handling

[](#error-handling)

Operations on the `Result` class raise `UnexpectedStatus` exceptions. Here's how to access their status and reason:

```
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();
}
```

### Authentication

[](#authentication)

Basic authentication is supported by embedding the credentials in the endpoint URL:

```
use webservices\rest\Endpoint;

$api= new Endpoint('https://user:pass@api.example.com/');
```

Bearer tokens can also be embedded in the endpoint URL:

```
use webservices\rest\Endpoint;

$api= new Endpoint('https://token@api.example.com/');
```

Other header-based authentication values can be passed along as follows:

```
use webservices\rest\Endpoint;

$api= (new Endpoint('https://api.example.com/'))->with(['X-API-Key' => $key]);
```

### Compression

[](#compression)

This library handlees compressed data transparently, sending an *Accept-Encoding* header containing compression algorithms supported in the PHP setup (*based on loaded extensions like e.g. [zlib](https://www.php.net/zlib)*) and using the *Content-Encoding* response header to determine which algorithm to select.

```
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);
```

### Testability

[](#testability)

This library also includes facilities to ease writing unittests for code making REST API calls. By using the *TestEndpoint* class and supplying it with routes it should respond to, various scenarios can be easily tested without the need for HTTP protocol and I/O overhead.

```
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
```

###  Health Score

54

—

FairBetter than 97% of packages

Maintenance83

Actively maintained with recent releases

Popularity28

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity75

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~60 days

Recently: every ~81 days

Total

46

Last Release

85d ago

Major Versions

v1.0.3 → v2.0.02020-04-10

v2.3.0 → v3.0.02021-10-21

v3.2.0 → v4.0.02021-12-03

v4.0.0 → v5.0.02022-02-26

v5.8.1 → v6.0.02025-05-04

PHP version history (3 changes)v0.1.0PHP &gt;=5.6.0

v2.0.0PHP &gt;=7.0.0

v6.0.0PHP &gt;=7.4.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/07d18d882c8b4aaf3466432f64018214f2771eda333202175431ee7233795376?d=identicon)[thekid](/maintainers/thekid)

---

Top Contributors

[![thekid](https://avatars.githubusercontent.com/u/696742?v=4)](https://github.com/thekid "thekid (271 commits)")

---

Tags

basic-authenticationbearer-authenticationbrotlibzip2compressionfile-uploadgziphttpjsonno-xmlphp7php8restrest-clientxp-frameworkmodulexp

### Embed Badge

![Health badge](/badges/xp-forge-rest-client/health.svg)

```
[![Health](https://phpackages.com/badges/xp-forge-rest-client/health.svg)](https://phpackages.com/packages/xp-forge-rest-client)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
