Weave 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 Laravel Package

avris/http

Lightweight HTTP client for PHP/Laravel with a clean, fluent API for making requests and working with responses. Designed for simple integrations, sane defaults, and easy customization of headers, query params, timeouts, and body formats.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require avris/http
    

    No service provider registration is required—this is a standalone package.

  2. First Use Case: Create a request and send it via a client:

    use Avris\Http\Request;
    use Avris\Http\Client;
    
    $request = new Request('GET', 'https://api.example.com/users');
    $client = new Client();
    $response = $client->send($request);
    
    // Extract data
    $data = $response->json();
    
  3. Where to Look First:

    • src/Request.php: Core request builder with methods like withHeader(), withBody().
    • src/Response.php: Response handling (e.g., json(), status()).
    • src/Client.php: Low-level transport (can be swapped, e.g., for Guzzle/Symfony).
    • src/Middleware/: Built-in middleware (e.g., RetryMiddleware, JsonMiddleware).

Implementation Patterns

Core Usage Patterns

  1. Immutable Request Building:

    $request = (new Request('POST', '/users'))
        ->withHeader('Accept', 'application/json')
        ->withHeader('Authorization', 'Bearer token')
        ->withBody(json_encode(['name' => 'John']));
    
  2. Middleware Stack (Laravel-Inspired):

    $client = new Client();
    $client->pushMiddleware(new RetryMiddleware(3)); // Retry failed requests
    $client->pushMiddleware(new JsonMiddleware());   // Auto-encode/decode JSON
    
  3. Response Transformation:

    $response = $client->send($request);
    $data = $response->json(); // Parse JSON body
    $status = $response->status(); // Get HTTP status code
    
  4. Integration with Laravel Controllers:

    use Avris\Http\Client;
    use Illuminate\Support\Facades\Http as LaravelHttp;
    
    // Option 1: Standalone usage
    $client = new Client();
    $response = $client->get('https://api.example.com/data');
    
    // Option 2: Wrap Laravel's HTTP client (if needed)
    $laravelClient = new class extends Client {
        protected function createTransport() {
            return new LaravelHttp();
        }
    };
    
  5. Testing with Mocks:

    // Mock a response for unit tests
    $mockResponse = new Response(200, [], '{"id": 1}');
    $client->setMockResponse($mockResponse);
    
    $response = $client->get('/test');
    $this->assertEquals(1, $response->json()['id']);
    

Workflows

  • API Client Layer: Create a dedicated service class to encapsulate API logic:

    class StripeService {
        protected $client;
    
        public function __construct(Client $client) {
            $this->client = $client;
        }
    
        public function createCustomer(array $data) {
            $request = (new Request('POST', '/customers'))
                ->withHeader('Authorization', 'Bearer ' . config('stripe.key'))
                ->withBody(json_encode($data));
    
            return $this->client->send($request)->json();
        }
    }
    
  • Request/Response Middleware: Use middleware to add cross-cutting concerns (e.g., logging, auth):

    $client->pushMiddleware(function ($request, callable $next) {
        $start = microtime(true);
        $response = $next($request);
        $duration = microtime(true) - $start;
    
        // Log request/response
        logger()->info("HTTP call took {$duration}s", [
            'method' => $request->method(),
            'url' => $request->url(),
            'status' => $response->status(),
        ]);
    
        return $response;
    });
    
  • Transport Abstraction: Swap the underlying HTTP client (e.g., Guzzle, Symfony, or cURL):

    // Use Guzzle as the transport
    $client = new Client(new GuzzleTransport());
    

Gotchas and Tips

Pitfalls

  1. Immutable Requests:

    • Requests are immutable by design. Use method chaining to modify them:
      // ❌ Won't work (requests are immutable)
      $request->withHeader('X-Test', '123');
      $request->withHeader('X-Test', '456'); // Overwrites previous header
      
      // ✅ Correct (creates a new request)
      $request = $request->withHeader('X-Test', '123');
      $request = $request->withHeader('X-Test', '456');
      
  2. Middleware Order:

    • Middleware executes in LIFO order (last pushed = first executed). Test your stack:
      $client->pushMiddleware($middleware1); // Executes second
      $client->pushMiddleware($middleware2); // Executes first
      
  3. Response Parsing:

    • Response::json() throws an exception if the body isn’t valid JSON. Handle it gracefully:
      try {
          $data = $response->json();
      } catch (JsonException $e) {
          $data = $response->text(); // Fallback to raw text
      }
      
  4. Transport Lock-In:

    • The default transport is a simple cURL wrapper. For advanced features (e.g., async, streaming), you’ll need to implement a custom transport (e.g., Guzzle or Symfony).
  5. Laravel Integration Quirks:

    • No built-in Laravel support: The package doesn’t extend Illuminate\Http\Request or Response. Use it alongside Laravel’s native classes or create adapters.
    • Middleware conflicts: Avoid mixing avris/http middleware with Laravel’s middleware pipeline unless explicitly designed for it.

Debugging Tips

  1. Log Requests/Responses: Add a middleware to log raw request/response data:

    $client->pushMiddleware(function ($request, callable $next) {
        logger()->debug('Request:', [
            'method' => $request->method(),
            'url' => $request->url(),
            'headers' => $request->headers()->all(),
            'body' => $request->body(),
        ]);
    
        $response = $next($request);
    
        logger()->debug('Response:', [
            'status' => $response->status(),
            'headers' => $response->headers()->all(),
            'body' => $response->body(),
        ]);
    
        return $response;
    });
    
  2. Check Status Codes: Use Response::isSuccessful() or Response::isClientError() to handle errors:

    if (!$response->isSuccessful()) {
        throw new RuntimeException("HTTP error: {$response->status()}");
    }
    
  3. Handle Redirects: The default transport does not follow redirects. Use a middleware or custom transport if needed:

    $client->pushMiddleware(new FollowRedirectsMiddleware());
    

Extension Points

  1. Custom Transports: Implement the TransportInterface to use other HTTP clients:

    class GuzzleTransport implements TransportInterface {
        public function send(Request $request): Response {
            $guzzleResponse = $this->client->request(
                $request->method(),
                $request->url(),
                [
                    'headers' => $request->headers()->all(),
                    'body' => $request->body(),
                ]
            );
    
            return new Response(
                $guzzleResponse->getStatusCode(),
                $guzzleResponse->getHeaders(),
                $guzzleResponse->getBody()->getContents()
            );
        }
    }
    
  2. Request/Response Factories: Extend the Request or Response classes to add custom methods:

    class CustomRequest extends Request {
        public function withAuthToken(string $token): self {
            return $this->withHeader('Authorization', "Bearer {$token}");
        }
    }
    
  3. Middleware Utilities: Create reusable middleware for common tasks (e.g., rate limiting, retries):

    class RateLimitMiddleware implements MiddlewareInterface {
        public function __invoke(Request $request, callable $next): Response {
            // Check rate limits
            if ($this->isOverLimit($request)) {
                return new Response(429, [], 'Too Many Requests');
            }
            return $next($request);
        }
    }
    

Configuration Quirks

  1. Default Headers: Set global default headers via middleware:

    $client->pushMiddleware(function ($request) {
        return $request->withHeader('User-Agent', 'MyApp/1.0');
    });
    
  2. Timeouts: Configure timeouts in the transport layer (e.g., cURL options or Guzzle config).

  3. SSL Verification: Disable SSL verification only for testing (never in production):

    $client = new Client(new CurlTransport([
        CURLOPT_SSL_VERIFYPEER
    
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.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums