---
title: "DI and actions — HTTP Client Rate Limits for Laravel | Roundly"
description: "Inject RateLimitManager instead of calling the facade, or wire a RateLimit by hand — the package has no action classes."
url: https://roundly-consulting.com/open-source/docs/http-client-rate-limits-for-laravel/without-facade
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[HTTP Client Rate Limits for Laravel](https://roundly-consulting.com/open-source/docs/http-client-rate-limits-for-laravel.md)

# DI and actions

The facade is the shortest route and the recommended default, not the only one. The same API is available as RoundlyConsulting\\HttpClientRateLimits\\RateLimitManager — the facade root, bound as a singleton — which you can inject through the constructor: an explicit dependency and no static calls.

There is no third, action-based entry point: the package has no action classes, because a limit is a middleware object the manager builds, not a use case. So there is no facade method → action table either.

## Inject the manager

```php
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;
use RoundlyConsulting\HttpClientRateLimits\RateLimitManager;

final class OrdersClient
{
    public function __construct(private RateLimitManager $rateLimits) {}

    public function orders(string $account): Response
    {
        return Http::withMiddleware($this->rateLimits->perSecond(5)->by($account))
            ->get('https://api.example.com/orders');
    }
}
```

```php
// Every facade method exists on the injected manager:
$limit   = $this->rateLimits->profile('github');
$seconds = $this->rateLimits->retryAfter($response);
$queued  = $this->rateLimits->releasingJob($job)->perSecond(5);
```

RateLimits::fake() returns a RateLimitsFake — a RateLimitManager subtype — and swaps it into the container, so an injected manager and Http::rateLimit() receive the fake as well.

## Build a limit by hand

When you need full control, compose a RateLimit from a Limit, a Store and a Deferrer yourself:

```php
use RoundlyConsulting\HttpClientRateLimits\Deferrer\SleepDeferrer;
use RoundlyConsulting\HttpClientRateLimits\Limit;
use RoundlyConsulting\HttpClientRateLimits\Limiter;
use RoundlyConsulting\HttpClientRateLimits\RateLimit;
use RoundlyConsulting\HttpClientRateLimits\Store\RedisStore;

$rateLimit = new RateLimit(new Limiter(
    new Limit(key: 'acct-1', maxAttempts: 5, timespan: 'second'),
    new RedisStore('default'),
    new SleepDeferrer,
));

Http::withMiddleware($rateLimit)->get('https://api.example.com/things');
```

A hand-built limit uses exactly the store and deferrer you pass: the configured defaults don’t apply to it, and neither do the fake’s shared store and non-sleeping deferrer.

## Internal classes

RetryAfter is @internal — parse the header with RateLimits::retryAfter() (or $manager->retryAfter()) instead.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/http-client-rate-limits-for-laravel.md)
