discord-php/http
Async PHP HTTP client for the Discord REST API (PHP 7.4+). Works with an event loop (e.g., React) and PSR-3 logging. Provides get/post/put/patch/delete plus queueRequest, returns decoded JSON promises, and includes Endpoint constants with bind() for rate-limit buckets.
Install the Package:
composer require discord-php/http
Ensure monolog is installed for logging:
composer require monolog/monolog
Configure the Event Loop:
Use Laravel’s service container to bind the ReactPHP loop and HTTP client. Add this to config/app.php under providers:
Discord\Http\ServiceProvider::class,
Publish the config (if needed) and update config/discord-http.php:
return [
'token' => env('DISCORD_BOT_TOKEN'),
'driver' => 'react',
'logger' => [
'channel' => 'single',
'path' => storage_path('logs/discord.log'),
],
];
Register the HTTP Client:
In AppServiceProvider@boot():
public function boot()
{
$loop = \React\EventLoop\Factory::create();
$logger = \Monolog\Logger::create('discord', [
new \Monolog\Handler\StreamHandler(storage_path('logs/discord.log'))
]);
$http = new \Discord\Http\Http(config('discord-http.token'), $loop, $logger);
$http->setDriver(new \Discord\Http\Drivers\React($loop));
$this->app->singleton('discord.http', function () use ($http) {
return $http;
});
}
First Use Case: Fetch Bot Info Create a service or controller method:
use Discord\Http\Endpoint;
public function getBotInfo()
{
$http = app('discord.http');
$endpoint = Endpoint::USER_BOT;
$http->get($endpoint)->done(
function ($response) {
return response()->json($response);
},
function ($e) {
return response()->json(['error' => $e->getMessage()], 500);
}
);
}
Run the Event Loop: For CLI commands or Octane workers, ensure the loop runs:
$loop = \React\EventLoop\Factory::create();
$loop->run();
Queue Requests for Background Processing: Use Laravel queues to offload Discord API calls:
// Dispatch a job
dispatch(new SendDiscordMessage($channelId, $message));
// Job implementation
public function handle()
{
$http = app('discord.http');
$endpoint = Endpoint::bind(Endpoint::CHANNEL_MESSAGE, $this->channelId);
$http->post($endpoint, json_encode(['content' => $this->message]))->done(
function () { /* Success */ },
function ($e) { Log::error($e->getMessage()); }
);
}
Rate-Limit Bucketing:
Always use Endpoint::bind() for parameterized endpoints to ensure proper rate-limit bucketing:
// Correct: Bucketed by channel/message
$endpoint = Endpoint::bind(Endpoint::CHANNEL_MESSAGE, $channelId, $messageId);
// Incorrect: May not bucket correctly
$endpoint = Endpoint::CHANNEL_MESSAGE . "/$messageId";
Error Handling and Retries: Implement exponential backoff for retries:
$attempts = 0;
$maxAttempts = 3;
$delay = 100; // ms
$http->get($endpoint)->done(
function ($response) { /* Success */ },
function ($e) use (&$attempts, &$delay, $maxAttempts, $endpoint) {
if ($attempts < $maxAttempts) {
$attempts++;
$delay *= 2;
$this->loop->addTimer($delay / 1000, function () use ($endpoint) {
$this->fetchData($endpoint);
});
}
}
);
Integration with Laravel Events: Trigger Laravel events on Discord API responses:
$http->get($endpoint)->done(
function ($response) {
event(new DiscordBotInfoFetched($response));
},
function ($e) {
event(new DiscordApiError($e));
}
);
Webhook Handling: Use async requests for webhook deliveries to avoid blocking:
public function handleWebhook($payload)
{
$http = app('discord.http');
$endpoint = Endpoint::WEBHOOK_EXECUTE . '/' . $this->webhookId . '/' . $this->webhookToken;
$http->post($endpoint, json_encode($payload))->done(
function () { /* Success */ },
function ($e) { Log::error('Webhook failed: ' . $e->getMessage()); }
);
}
Octane Integration: Run the ReactPHP loop in Laravel Octane for high-performance async handling:
// In Octane worker
$loop = \React\EventLoop\Factory::create();
$http = new \Discord\Http\Http(config('discord-http.token'), $loop, $logger);
$http->setDriver(new \Discord\Http\Drivers\React($loop));
// Process requests
$loop->run();
Connection Pooling: Reuse the HTTP client instance across requests to avoid overhead:
// Singleton in service container (as shown in Getting Started)
$this->app->singleton('discord.http', function () {
return new \Discord\Http\Http(config('discord-http.token'), $loop, $logger);
});
Batching Requests:
Use queueRequest for batching multiple API calls:
$http->queueRequest('GET', Endpoint::GUILD_MEMBERS . '/' . $guildId, null, [
'limit' => 100
])->done(function ($response) {
// Process batch
});
Middleware for Auth/Logging: Create a middleware to add headers or log requests:
$http->get($endpoint)->done(
function ($response) {
Log::info('Discord API Response', ['endpoint' => $endpoint, 'response' => $response]);
}
);
Event Loop Must Run:
$loop->run() will cause all async requests to hang.// In Artisan commands or workers
$loop->run();
Rate-Limit Bucketing:
Endpoint::bind() for parameterized endpoints can lead to incorrect rate-limit bucketing and API bans.// Correct
$endpoint = Endpoint::bind(Endpoint::CHANNEL_MESSAGE, $channelId, $messageId);
// Incorrect (may not bucket correctly)
$endpoint = Endpoint::CHANNEL_MESSAGE . "/$channelId/messages/$messageId";
Async Callbacks Blocking:
done() callbacks will stall the event loop.React\Promise\Timer for delays:
$http->get($endpoint)->done(function ($response) {
// Non-blocking: Dispatch a job
dispatch(new ProcessDiscordResponse($response));
});
Token Leaks:
.env and never log tokens:
// Avoid
Log::info('Token: ' . config('discord-http.token'));
// Do
Log::info('Using Discord HTTP client');
Driver Compatibility:
PHP 8+ Type Safety:
composer require discord-php/http:^10.9
Endpoint Updates:
How can I help you explore Laravel packages today?