PHPackages                             nimbly/shuttle - 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. nimbly/shuttle

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

nimbly/shuttle
==============

Simple PSR-18 HTTP client.

2.0(1y ago)54.0M—4.9%14MITPHPPHP ^8.2CI passing

Since Apr 6Pushed 1y ago2 watchersCompare

[ Source](https://github.com/nimbly/Shuttle)[ Packagist](https://packagist.org/packages/nimbly/shuttle)[ RSS](/packages/nimbly-shuttle/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (6)Versions (16)Used By (14)

Shuttle
=======

[](#shuttle)

[![Latest Stable Version](https://camo.githubusercontent.com/b54298916dc57db3347dce3616bcdc7ece214c1d8619951a2224009b87887d87/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6e696d626c792f53687574746c652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/nimbly/Shuttle)[![GitHub Workflow Status](https://camo.githubusercontent.com/6f3054c41271bb3027eff618bffd788b621113e84661ba5329b748777fa48230/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6e696d626c792f73687574746c652f636f7665726167652e796d6c3f7374796c653d666c61742d737175617265)](https://github.com/nimbly/Shuttle/actions/workflows/coverage.yml)[![Codecov branch](https://camo.githubusercontent.com/3f881718b4460a1818a8b8bb20c639ae04455d81d8a3178afc4dc0b9b71bc6b3/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636f762f632f6769746875622f6e696d626c792f73687574746c652f6d61737465723f7374796c653d666c61742d737175617265)](https://app.codecov.io/github/nimbly/Shuttle)[![License](https://camo.githubusercontent.com/d5d8d5758ee7f71a2106e9a1c01ceb0339d78d1ff754d6a36678603eb2a4d810/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6e696d626c792f53687574746c652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/nimbly/Shuttle)

A simple PSR-18 HTTP client library.

Requirements
------------

[](#requirements)

- PHP 8.2+
- ext-curl

Installation
------------

[](#installation)

```
composer require nimbly/shuttle
```

Features
--------

[](#features)

- Responses create php://temp response body stream and swap to disk when necessary.
- cURL (default) and Stream Context handlers supported.
- Middleware support out of the box.
- Easy body transformations when creating requests with JsonBody and FormBody helper classes.
- Support for multipart form bodies.

Not features
------------

[](#not-features)

- Asynchronous calls.

A note on PSR-7 and PSR-17
--------------------------

[](#a-note-on-psr-7-and-psr-17)

Shuttle makes use of PSR-7 HTTP Message and will default to using `nimbly/capsule`. You can override this by providing your perferred choice in PSR-7 implementations by passing PSR-17 HTTP Factories instances into the constructor of `Shuttle`.

```
$http_factory = new GuzzleHttp\Psr7\HttpFactory;

$shuttle = new Shuttle(
	requestFactory: $http_factory,
	responseFactory: $http_factory,
	streamFactory: $http_factory,
	uriFactory: $http_factory,
);
```

Making requests: The easy way
-----------------------------

[](#making-requests-the-easy-way)

The quickest and easiest way to begin making requests in Shuttle is to use the HTTP method name:

```
use Nimbly\Shuttle\Shuttle;

$shuttle = new Shuttle;

$response = $shuttle->get("https://www.google.com");
$response = $shuttle->post("https://example.com/search", "Form data"));
```

Shuttle has built-in methods to support the major HTTP verbs: get, post, put, patch, delete, head, and options. However, you can make **any** HTTP verb request using the **request** method directly.

```
$response = $shuttle->request("connect", "https://api.example.com/v1/books");
```

Handling responses
------------------

[](#handling-responses)

Responses in Shuttle implement PSR-7 ResponseInterface and as such are streamable resources.

```
$response = $shuttle->get("https://api.example.com/v1/books");

echo $response->getStatusCode(); // 200
echo $response->getReasonPhrase(); // OK

$body = $response->getBody()->getContents(); // {"title": "Do Androids Dream of Electric Sheep?", "author": "Philip K. Dick"}
```

Handling failed requests
------------------------

[](#handling-failed-requests)

Shuttle will throw a `RequestException` by default if the request failed. This includes things like host name not found, connection timeouts, etc.

Responses with HTTP 4xx or 5xx status codes *will not* throw an exception and must be handled properly within your business logic.

Making requests: The PSR-7 way
------------------------------

[](#making-requests-the-psr-7-way)

If code reusability and portability is your thing, future proof your code by making requests the PSR-7 way. Remember, PSR-7 stipulates that Request and Response messages be immutable.

```
// Build Request message with your favorite PSR-7 library.
$request = new Request("get", "https://www.example.com");

// Send the Request.
$shuttle = new Shuttle;
$response = $shuttle->sendRequest($request);
```

Using the `sendRequest()` method *does not* apply any `base_url` or default `headers` passed into the Shuttle constructor. However, the request is still passed through the middleware chain.

Request bodies
--------------

[](#request-bodies)

An easy way to submit data with your request is to use the `Nimbly\Shuttle\Body\*` helper classes. These classes will automatically transform the data, convert to a **BufferStream**, and set a default **Content-Type** header on the request.

The request bodies supported are:

- `JsonBody` Converts an associative array or instance of `JsonSerializable` into JSON and sets the `Content-Type` header to `application/json`.
- `FormBody` Converts an associative array into a query string, sets `Content-Type` header to `application/x-www-form-urlencoded`.

To submit a JSON payload with a request:

```
use Nimbly\Shuttle\Body\JsonBody;

$book = [
    "title" => "Breakfast Of Champions",
    "author" => "Kurt Vonnegut",
];

$shuttle->post("https://api.example.com/v1/books", new JsonBody($book));
```

Middleware
----------

[](#middleware)

Shuttle supports dual (aka double) pass middleware by implementing `MiddlewareInterface`. The request and response instance are both available to the middleware and can be manipulated to your specific needs.

```
class AuthMiddleware implements MiddlewareInterface
{
	public function __construct(
		private string $api_key)
	{
	}

	public function process(RequestInterface $request, callable $next): ResponseInterface
	{
		// Add the Authorization header with every outgoing request.
		$request = $request->withAddedHeader("Authorization", "Bearer " . $this->api_key);

		// Pass request object to next middleware layer.
		$response = $next($request);

		// Return response back with custom header added.
		return $response->withAddedHeader("X-Custom-Header", "Foo");
	}
}
```

You may add as many middleware layers as you need and pass them to the Shuttle constructor. The middleware are executed in the order given.

```
$shuttle = new Shuttle(
	middleware: [
		new AuthMiddleware(\getenv("API_KEY")),
		new FooMiddleware,
		new BazMiddleware,
	]
);
```

###  Health Score

52

—

FairBetter than 96% of packages

Maintenance44

Moderate activity, may be stable

Popularity46

Moderate usage in the ecosystem

Community19

Small or concentrated contributor base

Maturity80

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 96.4% 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 ~154 days

Recently: every ~73 days

Total

15

Last Release

445d ago

Major Versions

0.6 → 1.02023-04-06

1.x-dev → 2.x-dev2024-12-04

PHP version history (6 changes)0.1PHP ^7.2

0.3.3PHP &gt;=7.2

0.5PHP ^7.4|^8.0

0.6PHP ^7.3|^8.0

1.0PHP ^8.0

2.x-devPHP ^8.2

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/723164?v=4)[Brent Scheffler](/maintainers/brentscheffler)[@brentscheffler](https://github.com/brentscheffler)

---

Top Contributors

[![brentscheffler](https://avatars.githubusercontent.com/u/723164?v=4)](https://github.com/brentscheffler "brentscheffler (81 commits)")[![8ctopus](https://avatars.githubusercontent.com/u/13252042?v=4)](https://github.com/8ctopus "8ctopus (3 commits)")

---

Tags

http-clienthttp-requestshttp-responsepsr-18httpclientcurlhttp clientpsr-18stream context

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/nimbly-shuttle/health.svg)

```
[![Health](https://phpackages.com/badges/nimbly-shuttle/health.svg)](https://phpackages.com/packages/nimbly-shuttle)
```

###  Alternatives

[aplus/http-client

Aplus Framework HTTP Client Library

2161.6M1](/packages/aplus-http-client)[amphp/http-client-psr7

PSR-7 adapter for Amp's HTTP client.

1454.7k4](/packages/amphp-http-client-psr7)[sunrise/http-client-curl

A simple cURL client implementing PSR-18.

187.5k](/packages/sunrise-http-client-curl)

PHPackages © 2026

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