response()->acmeFailure(...) senza richiedere che i controller estendano una classe base.
Questa pagina si basa sulla documentazione ufficiale di Laravel nel branch predefinito 13.x e sull’implementazione ufficiale dell’ultima release del Framework, v13.40.0, verificate l’8 novembre 2026. Partendo dalle basi di Risposte e del trait Macroable, tratta i confini da tenere presenti quando mantieni una macro come API pubblica di un pacchetto distribuito.
Si registra sulla Factory, non sulla risposta
Il nomeResponse indica sia una facade che richiede la costruzione di una risposta sia la classe della risposta HTTP generata. Ciò che Response::macro() della documentazione ufficiale estende è ResponseFactory, la classe in cui viene risolta la facade.
response() senza argomenti restituisce la Factory. Invece response('corpo') e response(null) restituiscono una risposta creata con make(), quindi non chiamano la stessa destinazione.
Pubblicare un’API di costruzione per il JSON di errore
Registrarla in un service provider
Registra una macro con il prefisso del pacchetto nel metodoboot() di src/HttpServiceProvider.php. Per sapere come viene caricato il provider, consulta Discovery dei pacchetti.
Il contratto pubblico di questo esempio è un JSON con error.code ed error.message, insieme a uno stato HTTP compreso tra 400 e 599. Questa restrizione sullo stato non è un limite del meccanismo delle macro di Laravel. È il pacchetto a definirla per un’API dedicata agli errori.
runningInConsole() negata. Anche i test di funzionalità HTTP vengono eseguiti dalla CLI.
Un provider che si occupa solo di questa registrazione non deve nemmeno essere un provider differito in attesa della risoluzione di un servizio. Per il funzionamento della registrazione differita, consulta Service provider differiti.
Chiamarla da un controller
Dopo che la logica di business ha rilevato un conflitto, passa il codice di errore scelto e un messaggio per l’utente.409 e il JSON ha la forma seguente. Come con un normale json(), il Content-Type è application/json.
La macro costruisce solo le risposte nei punti in cui la chiami. Non converte automaticamente le eccezioni di validazione o gli errori di autenticazione in questo formato. Non aggiunge neanche alcun passaggio tra HTML e JSON in base all’header
Accept.Il $this della Closure e il percorso di chiamata
La Factory usa Macroable. Quando chiami un metodo non definito su un’istanza, __call() cerca la macro registrata e ricollega una normale Closure all’istanza su cui è stata chiamata.
Anche se il codice di registrazione si trova in un metodo del service provider, $this a runtime è la Factory e non il service provider. Per questo $this->json() nell’esempio chiama il normale metodo della Factory.
- Definisci le macro che usano
$thiscon una normalefunction (...) { ... }. Unastatic functionnon ha il$thisdi istanza. - Se registri un oggetto invocabile, non viene ricollegato come una Closure. Fai in modo che sia l’oggetto stesso a ricevere le dipendenze necessarie, ad esempio tramite il proprio costruttore.
- Gli argomenti della macro sono quelli passati dal chiamante. Anche se dichiari il tipo
Requesto simili, Macroable non lo inietta automaticamente dal container.
Response::acmeFailure() sembra statica, ma internamente viene inoltrata all’istanza della Factory. Invece Illuminate\Routing\ResponseFactory::acmeFailure() sulla classe concreta è una vera chiamata statica, e __callStatic() collega la Closure senza istanza. Una macro come questa, che usa $this->json(), non supporta le chiamate statiche sulla classe concreta.
Trattare le collisioni di nomi come un problema di compatibilità
macro() si limita ad assegnare un valore in un array statico indicizzato per nome. Registrare un nome esistente non genera alcun avviso.
Scegli un nome che identifichi il tuo pacchetto, come
acmeFailure, invece di un nome generico come failure. Quando aggiorni Laravel, controlla anche le collisioni con i metodi reali usando method_exists(ResponseFactory::class, 'acmeFailure').
Se controlli hasMacro() e salti la registrazione senza condizioni, rischi di usare l’implementazione di un altro pacchetto come se fosse la tua API. Solo quando rendi “l’applicazione può sovrascriverla registrandola prima” parte della specifica, pubblica tale priorità insieme agli argomenti e al valore restituito richiesti. L’esempio sopra segue la politica di registrare la definizione del pacchetto ogni volta che il provider si avvia.
Separare lo stato di registrazione dalla durata delle risposte
Il registro delle macro è una proprietà statica della Factory. Ricreare la Factory o cancellare l’istanza risolta della facade non svuota questo registro. Lo stato di registrazione può persistere anche nei test che ricreano l’applicazione all’interno dello stesso processo PHP. D’altra parte, la macro dell’esempio fa creare ajson() una nuova JsonResponse a ogni chiamata. Ciò che viene condiviso è la logica di costruzione, non il corpo o gli header della risposta.
Questi sono i confini da rispettare nei worker di lunga durata.
- Non catturare la Request corrente, l’utente autenticato o il tenant con
use (...)al momento della registrazione. Passa questi valori come argomenti al momento della chiamata. - Non riutilizzare una risposta creata al momento della registrazione. Restituisci ogni volta una nuova risposta.
- Se catturi la configurazione come valore al momento della registrazione, includi nella specifica che quel valore viene mantenuto nel processo.
- Dopo aver aggiornato il pacchetto, riavvia i processi di lunga durata affinché il nuovo codice di registrazione abbia effetto.
Testare il contratto HTTP con valori restituiti reali
In un’applicazione di test Laravel 13 in grado di caricare il pacchetto tramite Composer, aggiungi il seguentetests/Feature/ResponseMacroTest.php. Per Tests\TestCase e le basi dei test HTTP, consulta Test HTTP. Per preparare un ambiente di pacchetto autonomo, consulta Testare i pacchetti.
Response::shouldReceive('acmeFailure'), la registrazione della macro, il collegamento della Closure e la generazione del JSON non vengono eseguiti. Tieni separata la verifica del numero di chiamate e controlla la vera risposta HTTP come mostrato sopra.
Inoltre, considera il corpo, lo stato e gli header ricevuti dagli utenti come oggetto di compatibilità.
- Mantieni
error.codestabile per i controlli automatici e distinguilo dalle modifiche al messaggio visualizzato. - I nomi degli argomenti vengono usati come argomenti con nome, quindi verifica l’impatto di una loro modifica come per i valori predefiniti o l’ordine.
- Restituisci le risposte senza corpo, come
204, con un’altra API comenoContent(), non come JSON di errore. - Se consenti estensioni che modificano il
Content-Typetramite header personalizzati, mantienilo coerente con il formato del corpo. - Se il tuo obiettivo è la serializzazione dei dati o la paginazione, valuta anche le risorse API di Eloquent invece di reimplementarle solo con le macro.
Checklist per la manutenzione a lungo termine
- Nelle combinazioni Laravel 13 supportate, il provider si avvia e la macro può essere chiamata sia dall’helper sia dalla facade.
- Il nome della macro non entra in collisione con altre registrazioni o con metodi reali della Factory.
- La compatibilità di chiavi JSON, stato HTTP, header, valori predefiniti e argomenti con nome è coperta da test.
- Le chiamate consecutive non condividono risposte e al momento della registrazione non vengono conservate informazioni su Request o utente.
- I test che reimpostano le registrazioni sono isolati dagli altri pacchetti.
- Il riavvio dei processi di lunga durata fa parte della procedura di aggiornamento.
Fonti primarie consultate
- Documentazione ufficiale di Laravel: Response macros e JSON responses (13.x)
- Documentazione ufficiale di Laravel: Package development (13.x)
- La facade Response e la sua destinazione di risoluzione (v13.40.0)
- Inoltro della Facade all’istanza (v13.40.0)
- L’helper response() (v13.40.0)
- Logica di costruzione di ResponseFactory (v13.40.0)
- Registrazione, collegamento e reset in Macroable (v13.40.0)
- Test ufficiali di Macroable (v13.40.0)