garlic/graphql-wrapper
A Laravel-friendly GraphQL wrapper for sending queries and mutations from PHP. Configure endpoints and headers, build requests fluently, and handle responses with clean, testable code—lightweight integration without heavy client dependencies.
Install the package and publish its config:
composer require vendor/package
php artisan vendor:publish --tag=package-config
Configure the broker connection and any application-wide defaults in config/package.php (or the relevant config/queue.php connection block). Clear cached config after changes:
php artisan config:clear
Where to look first
First use case: correlation IDs
The 1.1 release adds the ability to attach headers when enqueueing. The highest-value first use is propagating a correlation ID so logs across producer and consumer can be joined:
use Illuminate\Support\Str;
use Vendor\Package\Facades\Enqueue;
Enqueue::message(['order_id' => $order->id])
->header('x-correlation-id', (string) Str::uuid())
->header('x-tenant-id', tenant('id'))
->send();
If your package exposes a message factory or job bridge, confirm whether headers are set on the message builder or passed as the second argument to the enqueue call — the API shape is the main thing to verify before rolling it out.
Per-message headers for request-scoped data
Use headers for values that change per dispatch: correlation IDs, tenant IDs, locale, user/session references, schema versions, content type. Keep the message body for domain payload only.
Enqueue::message($payload)
->headers([
'x-correlation-id' => $correlationId,
'x-tenant-id' => tenant('id'),
'content-type' => 'application/json',
'x-schema-version' => '2',
])
->send();
Global defaults via config
Put stable metadata in config so every message carries it without repeating it at call sites:
// config/package.php
'headers' => [
'x-app' => env('APP_NAME'),
'x-env' => env('APP_ENV'),
'x-release' => env('APP_VERSION'),
],
Per-message headers should override defaults; verify merge precedence rather than assuming it.
Middleware / decorator for cross-cutting headers
If the package supports message middleware (or you wrap your own enqueue service), inject headers centrally. This keeps controllers and jobs clean and ensures nothing is dispatched without tracing metadata:
final class AttachTraceHeaders
{
public function handle($message, Closure $next)
{
return $next($message
->header('x-correlation-id', app('trace.id'))
->header('traceparent', app('trace.w3c')));
}
}
Consumer-side integration
Headers are only half the contract. On the consumer, read them into Laravel's logging/context so they appear in every downstream log line:
Log::withContext([
'correlation_id' => $headers['x-correlation-id'] ?? null,
'tenant_id' => $headers['x-tenant-id'] ?? null,
]);
If you bridge into Laravel jobs, attach headers before dispatch and read them in job middleware so retries and failures retain context.
Observability and multi-tenancy
The 1.1 feature is most valuable for:
traceparent propagation into non-Laravel consumers.Testing
Use the package's fake (or your own wrapper) and assert headers explicitly. Header regressions are silent otherwise:
Enqueue::fake();
dispatch(new SendOrder($order));
Enqueue::assertSent(OrderMessage::class, function ($message) {
return $message->headers()['x-tenant-id'] === 'acme';
});
Header values must be scalar
Most brokers coerce or reject arrays/objects. Cast booleans, enums, and IDs to strings at the call site. true may arrive as "1" or "true" depending on the transport — normalize on read.
Broker limits are real
Do not stuff JSON blobs into headers. If it is larger than a short scalar, it belongs in the payload.
Reserved and prefixed header names
Brokers reserve names (x-delay, x-death, ApproximateReceiveCount, AMQP properties). Avoid the x- prefix colliding with transport internals unless you control both ends. Check for case-insensitive collisions — AMQP and HTTP-style transports differ on casing.
Header casing and normalization
X-Tenant-Id and x-tenant-id may be treated as distinct or identical depending on the transport. Pick one convention (lowercase, hyphenated) and enforce it in the wrapper.
Config caching
Default headers defined in config will not reflect .env changes until php artisan config:clear. This is the most common "my headers disappeared" cause in deployed environments.
Retries and failed jobs
Confirm whether headers survive requeue and whether they are persisted in failed_jobs. Many Laravel queue integrations store only the payload, so a failed message retried from the database may lose its headers. If correlation matters for triage, log the headers on the consumer side as soon as the message is received.
Do not put secrets in headers
Headers are often visible in broker consoles, tracing UIs, and DLQ inspection tools. Treat them as metadata, not a side channel.
Upgrade compatibility
1.1 is an additive feature release: existing enqueue calls without headers should behave identically. No migration is required. The main risk is behavioral, not breaking — if your wrapper already injects headers through a different mechanism, audit for duplicate or conflicting keys.
Debugging checklist
php artisan queue:restart) after deploying header changes.Extension points
If the package exposes a message factory, a serializer, or middleware pipeline, prefer extending those over subclassing the enqueue facade. Custom serializers are the right place to normalize header casing and value types across all messages.
How can I help you explore Laravel packages today?