Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Http Client Laravel Package

amphp/http-client

Asynchronous HTTP client for PHP built on Revolt with fibers and concurrency. Supports HTTP/1 & HTTP/2, concurrent requests, connection pooling, redirects, gzip/deflate decoding, streaming bodies, TLS by default, cookies/sessions, proxies, and custom methods—no ext/curl dependency.

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Steps
1. **Installation**:
   ```bash
   composer require amphp/http-client

Optionally, install nghttp2 for HTTP/2 performance:

pecl install nghttp2
  1. First Request:

    use Amp\Http\Client\HttpClientBuilder;
    use Amp\Http\Client\Request;
    
    $client = HttpClientBuilder::buildDefault();
    $response = await $client->request(new Request('https://httpbin.org/get'));
    echo await $response->getBody()->buffer();
    
  2. Key Files:

    • vendor/amphp/http-client/src/ for core classes.
    • examples/ for practical use cases (e.g., concurrency/1-concurrent-fetch.php).
    • tests/ for edge-case validation.

First Use Case: Concurrent API Calls

use Amp\Http\Client\HttpClientBuilder;
use Amp\Http\Client\Request;

$client = HttpClientBuilder::buildDefault();
$requests = [
    new Request('https://httpbin.org/get'),
    new Request('https://httpbin.org/ip'),
    new Request('https://httpbin.org/user-agent'),
];

$responses = await $client->requestAll($requests);
foreach ($responses as $response) {
    echo await $response->getBody()->buffer();
}

Implementation Patterns

Core Workflow: Request-Response Cycle

  1. Build Client:

    $client = (new HttpClientBuilder)
        ->setConnectTimeout(5.0) // 5 seconds
        ->setTimeout(10.0)      // 10 seconds for full request
        ->build();
    
  2. Create Request:

    $request = new Request('https://api.example.com/data', 'POST');
    $request->setHeader('Content-Type', 'application/json');
    $request->setBody(json_encode(['key' => 'value']));
    
  3. Handle Response:

    $response = await $client->request($request);
    if ($response->getStatus() === 200) {
        $data = json_decode(await $response->getBody()->buffer(), true);
    }
    

Common Patterns

Streaming Large Responses

$response = await $client->request(new Request('https://example.com/large-file'));
$stream = $response->getBody();
while (!$stream->isFinished()) {
    $chunk = await $stream->read();
    // Process chunk (e.g., save to disk)
}

Retry Mechanism with Interceptors

use Amp\Http\Client\Interceptor\RetryRequests;

$client = (new HttpClientBuilder)
    ->intercept(new RetryRequests(3)) // Retry 3 times
    ->build();

Custom Headers via Interceptors

use Amp\Http\Client\Interceptor\SetRequestHeader;

$client = (new HttpClientBuilder)
    ->intercept(new SetRequestHeader('X-API-Key', 'your-key-here'))
    ->build();

HTTP/2 Pooling for Performance

$client = (new HttpClientBuilder)
    ->setMaxConnections(100) // Reuse connections
    ->build();

Form Data Submission

use Amp\Http\Client\Request;

$request = new Request('https://httpbin.org/post', 'POST');
$request->setBody(http_build_query([
    'username' => 'john',
    'password' => 'secret',
]));
$request->setHeader('Content-Type', 'application/x-www-form-urlencoded');

Integration with Laravel

  1. Service Provider:

    use Amp\Http\Client\HttpClientBuilder;
    use Illuminate\Support\ServiceProvider;
    
    class AmpHttpClientServiceProvider extends ServiceProvider {
        public function register() {
            $this->app->singleton('amp.http.client', function () {
                return (new HttpClientBuilder)
                    ->setConnectTimeout(5.0)
                    ->build();
            });
        }
    }
    
  2. Facade (Optional):

    // app/Facades/AmpHttp.php
    namespace App\Facades;
    
    use Illuminate\Support\Facades\Facade;
    
    class AmpHttp extends Facade {
        protected static function getFacadeAccessor() {
            return 'amp.http.client';
        }
    }
    
  3. Usage in Controllers:

    use App\Facades\AmpHttp;
    use Amp\Http\Client\Request;
    
    class ApiController extends Controller {
        public async function fetchData() {
            $response = await AmpHttp::request(new Request('https://api.example.com/data'));
            return response()->json(json_decode(await $response->getBody()->buffer(), true));
        }
    }
    

Gotchas and Tips

Pitfalls

  1. Blocking the Event Loop:

    • Issue: Forgetting await before request() or getBody()->buffer() will block the event loop.
    • Fix: Always use await:
      $response = await $client->request($request); // Correct
      // vs.
      $response = $client->request($request); // Blocks!
      
  2. Memory Leaks with Large Responses:

    • Issue: Buffering entire responses (buffer()) for large files (e.g., downloads) can exhaust memory.
    • Fix: Stream responses:
      $stream = $response->getBody();
      while (!$stream->isFinished()) {
          $chunk = await $stream->read();
          file_put_contents('output.bin', $chunk, FILE_APPEND);
      }
      
  3. Redirect Headers Lost:

    • Issue: Custom headers may be stripped during redirects if not set via interceptors.
    • Fix: Use interceptors for headers:
      $client = (new HttpClientBuilder)
          ->intercept(new SetRequestHeader('Authorization', 'Bearer token'))
          ->build();
      
  4. HTTP/2 Without nghttp2:

    • Issue: HTTP/2 falls back to HTTP/1.1 if nghttp2 is unavailable, reducing performance.
    • Fix: Install nghttp2 or accept the fallback:
      pecl install nghttp2
      
  5. Timeout Misconfiguration:

    • Issue: Default timeouts (e.g., setTimeout) may be too short for slow APIs.
    • Fix: Adjust timeouts per client:
      $client = (new HttpClientBuilder)
          ->setTimeout(30.0) // 30 seconds
          ->build();
      
  6. Immutable Assumption (PSR-7):

    • Issue: Request and Response objects are mutable (unlike PSR-7), leading to unexpected side effects.
    • Fix: Clone requests if modifying:
      $request = new Request('https://example.com');
      $modifiedRequest = clone $request;
      $modifiedRequest->setHeader('X-Custom', 'value');
      
  7. Cookie Handling:

    • Issue: Cookies are not automatically managed; use amphp/http-client-cookies.
    • Fix: Install and configure the cookie interceptor:
      composer require amphp/http-client-cookies
      
      use Amp\Http\Client\Interceptor\CookieHandler;
      
      $client = (new HttpClientBuilder)
          ->intercept(new CookieHandler())
          ->build();
      

Debugging Tips

  1. Log Requests/Responses: Use LogHttpArchive to debug:

    use Amp\Http\Client\EventListener\LogHttpArchive;
    
    $client = (new HttpClientBuilder)
        ->listen(new LogHttpArchive('/tmp/http-client.har'))
        ->build();
    

    View logs in HTTP Archive Viewer.

  2. Check Connection Pooling: Monitor active connections with:

    $client->getConnectionPool()->getConnectionCount();
    
  3. Validate Headers: Use getHeaders() to inspect headers:

    $headers = $response->getHeaders();
    dd($headers);
    
  4. Handle Exceptions: Wrap requests in try-catch:

    try {
        $response = await $client->request($request);
    } catch (\Amp\Http\Client\Exception\ClientException $e) {
        // Handle client errors (e.g., 4xx)
    } catch (\Amp\Http\Client\Exception\ServerException $e) {
        // Handle server errors (e.g., 5xx)
    } catch (\Amp\Http\Client\Exception\ConnectionException $e) {
        // Handle connection issues
    }
    

Extension Points

  1. Custom Interceptors: Extend ApplicationInterceptor or NetworkInterceptor for custom logic:
    use Amp\Http\Client\Interceptor\ApplicationInterceptor;
    use Amp\Http\Client\Request;
    use Amp\Http\Client\Response;
    
    class CustomInterceptor implements ApplicationInterceptor {
        public function onRequest(Request $request): void {
            $request->addHeader('X-Custom', 'value');
        }
    
        public
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope