mrgoodbytes8667/discord-response-bundle
A Laravel/PHP package that simplifies building and sending Discord responses, with helpers for structuring message payloads and handling Discord interaction responses. It makes integrating Discord bots and webhooks into your application more straightforward.
Install it (plain composer library, not a Laravel package)
composer require mrgoodbytes8667/discord-response-bundle:^0.15.1
This is not a Laravel service provider, and despite the "bundle" in the name it is not a Symfony bundle. There is no config/bundles.php entry, no config/app.php provider registration, no facade, no publishable config. It is a DTO/enum library that happens to depend on illuminate/collections (v0.15.1 raised that to ^8.69 | ^9.13 | ^10).
That version constraint is the first thing to check: it pins you to Laravel 8.69+, 9.13+, or 10.x — Laravel 11 is not supported yet. On Laravel 11 the install will either resolve to an older illuminate/collections (bad) or fail. Verify with composer why illuminate/collections after install.
Where to look first
src/ response/DTO classes — the typed Discord payloads (guild, user, message, channel, etc.). Since v0.15.1, collection-shaped fields will return Illuminate\Support\Collection, so ->getRoles()->map(...), ->pluck(), ->first() all work directly.src/Enum/ — channel types, message flags, intent bits, permission bits, API versions. This is the bulk of the package's value.composer.json — confirm the illuminate/collections resolution and the PHP floor.First use case
You are already calling Discord's REST API with Laravel's Http facade and getting back arrays. That is the pain point. Instead of:
$data = Http::withToken($token)->get("https://discord.com/api/v10/guilds/{$id}")->json();
echo $data['name'];
echo $data['roles'][0]['name'];
you hydrate a DTO and get typed getters with collection conveniences:
$guild = GuildResponse::fromArray(
Http::withToken($token)->get("/guilds/{$id}")->json()
);
echo $guild->getName();
echo $guild->getRoles()->first()->getName();
Pick one endpoint (guild fetch is ideal) and swap array access for getters. That tells you whether the DTO shapes match your API version and whether to roll it out further.
Thin adapter over the Laravel HTTP client
Keep the HTTP call and the hydration separate. The package ships shapes, not transport, so you keep full control of base URL, token, retries, and logging:
final class DiscordGuildFetcher
{
public function __construct(private string $token) {}
public function fetch(string $guildId): GuildResponse
{
return GuildResponse::fromArray(
Http::withToken($this->token)
->baseUrl('https://discord.com/api/v10')
->get("/guilds/{$guildId}")
->throw()
->json()
);
}
}
Bind this in a service provider and inject it where needed. Do not wrap the DTO in a fake HTTP client; the DTO is a value object, the fetcher is the I/O.
Collection-first consuming code
The v0.15.1 change is the day-to-day win: instead of foreach ($data['roles'] as $role), you get $guild->getRoles() returning an Illuminate\Support\Collection. That means ->filter(), ->firstWhere(), ->map(), ->pluck('name') all work naturally, and it composes with the rest of your Laravel app in a way plain arrays don't. For any endpoint returning lists (guilds, channels, roles, members), lean on this rather than iterating manually.
Enum-first conditionals
Replace Discord magic numbers everywhere. Anywhere you write if ($channel['type'] === 0) or if ($flags & 64), use the shipped enums:
if ($channel->getType() === DiscordChannelType::GUILD_TEXT) { /* ... */ }
if ($message->getFlags() & DiscordMessageFlags::EPHEMERAL->value) { /* ... */ }
This turns silent typos into compile-time errors and makes the codebase greppable. A grep of your existing code for numeric literals against Discord fields is a ready-made migration checklist.
Eloquent/collection boundary
If you persist hydrated DTO data (e.g. caching guild metadata), convert collections to plain arrays at the boundary with ->toArray(). Don't let Illuminate\Support\Collection instances leak into JSON responses by accident — they serialize fine for lists but can surprise you when nested inside other structures. When building outbound Discord payloads, always unwrap enums:
$payload = [
'content' => $text,
'flags' => DiscordMessageFlags::SUPPRESS_EMBEDS->value,
];
Never hand a bare enum case to Http::post() — it serialises to {} or throws.
Testing with fixtures
DTOs make excellent fixtures for feature tests. Commit a few real (anonymized) Discord JSON payloads under tests/fixtures/, hydrate a DTO, assert on getters. Because the collections now behave like Laravel collections, you can assert $guild->getRoles()->count() or ->first()->getName() directly in your test suite. When Discord changes a field, the fixture test fails before production does.
No Laravel 11 support yet. v0.15.1 caps at illuminate/collections ^10. If you're on Laravel 11, this package will either force an older collections version or refuse to install. Check before planning an upgrade — this is the single most likely blocker for a new Laravel project.
It's a library, not a package. No service provider, no config, no commands, no facade. Don't go looking for php artisan vendor:publish. Everything is new-ed or called statically from the classes you need. This is good (no boot overhead) but means you own the integration.
Pre-1.0 semver discipline. You are on 0.15.x, not 1.x. Under semver, minor bumps in a 0.x series can be breaking. Pin tightly with ^0.15.1 and commit the lock file. The previous assessment's advice to pin ^1.0 was wrong — no 1.0 exists.
License. NOASSERTION in composer.json — verify the actual license permits your use before it lands in a commercial codebase. This has not changed in v0.15.1.
API version drift. Discord's API evolves constantly. DTOs written for API v10 won't gain v11 fields automatically. When Discord adds a field, the typed object silently drops it. Mitigation: in the adapter, keep the raw array alongside the DTO so you can fall back to unknown fields:
$raw = Http::withToken($token)->get(...)->json();
$dto = GuildResponse::fromArray($raw);
// later, for fields the DTO doesn't know about:
$newField = $raw['some_new_field'] ?? null;
Nullability is Discord's fault, not the package's. Discord omits fields rather than sending null. getX() on a missing field may throw or return null depending on how the getter was typed. Check each return type you use and test against a fixture that's missing that field.
Enums are backed, not pure. Use ->value for HTTP bodies and bitwise math. Never compare an enum case with a raw int (=== will be false). Use from()/tryFrom() when parsing input, and prefer tryFrom() for forward compatibility — a new Discord channel type added tomorrow will crash from().
Rate limits and errors are out of scope. This library gives you shapes, not behaviour. It does not interpret 429 bodies, does not back off, does not expose Retry-After. Handle that in your Http layer (macros, middleware, or a dedicated retrying client). Treat the response bundle purely as a deserialisation layer.
Extension points are limited by design. Classes are likely final or close to it. If you need behaviour (e.g. a GuildResponse::getLargeIconUrl() helper), wrap the DTO in your own service rather than subclassing. That keeps your code upgradeable if upstream ever resumes.
Small surface area means vendoring is viable. Zero stars, zero dependents, sparse docs, slow cadence. Read src/ as the authoritative documentation before trusting the README. If maintenance stalls, the DTO and enum surface is small enough that forking into your own app/Discord/Dto/ and app/Discord/Enum/ namespace is a realistic escape hatch — especially now that you know it's just plain PHP over illuminate/collections.
How can I help you explore Laravel packages today?