Non è chiaro dalla domanda se esista o meno una separazione fisica tra il tuo front-end e l'API. Cioè, la tua applicazione è distribuita tra due server diversi. In tal caso, utilizzare HTTP per la comunicazione è un'opzione valida (sebbene esistano altri protocolli).
Mi sembra, tuttavia, che tu stia chiedendo di un'applicazione che non ha un limite fisico come quello descritto sopra. Nel qual caso può essere utile una discussione sugli obiettivi del disaccoppiamento e su come un'architettura ben progettata possa facilitare l'accoppiamento libero.
Innanzi tutto ci sarà sempre un certo livello di accoppiamento tra il tuo client e l'API. Sebbene l'obiettivo di dividere la tua applicazione in distinti concetti (ad esempio View
- > Application
- > Domain
- > Persistence
) è quello di favorire il disaccoppiamento in un modo che ognuno può cambiare indipendentemente l'uno dall'altro, questi livelli devono ancora comunicare. Cioè, al confine tra i livelli, deve esistere una conoscenza condivisa in termini di comunicazione (non implementazione).
Ad esempio, il tuo View
layer deve sapere come comporre un comando valido per il tuo Application
layer (o per lo meno sapere come chiedere come comporre un comando). Ciò significa che se cambi mai la firma del comando (i dati che devono essere inclusi in una richiesta) o la firma della query (i dati restituiti da una richiesta) nel tuo strato Application
, è probabile che questa modifica diventerà il tuo strato View
. Questo vale per tutti i confini architettonici ed è spesso il posto migliore per utilizzare le interfacce per illustrare chiaramente il contratto di comunicazione.
La seconda considerazione (di cui mi preoccupo di più) è che un'applicazione non dovrebbe richiedere a HTTP di comunicare con se stessa. In effetti, un'applicazione progettata correttamente non dovrebbe nemmeno essere "a conoscenza" del web in generale. Questo ha senso, giusto? L'intero punto di stratificazione dell'applicazione con un View
come livello concettuale più alto è quello di abilitare lo "scambio" di View
senza dover modificare nessuno dei livelli sottostanti! Ciò consente l'esistenza di molti% indipendenti di% co_de della tua applicazione (console, HTML, JSON, desktop, ecc.).
Okay, quindi come tutto questo si riferisce alla tua domanda? Penso che il problema che stiamo affrontando qui per la tua applicazione è che hai definito il contratto per la comunicazione tra i livelli solo in termini di HTTP. Cioè, non esiste una forma di comunicazione a livello di applicazione. Ad esempio, invece di tradurre un Views
in un comando più diretto (ad esempio HttpRequest
), potresti utilizzare FindOrder
come comando direttamente. Ciò che sta facendo questo è spingere la logica applicativa "verso l'alto" in un modo in cui i tuoi metodi HttpRequest
sono responsabili di "eseguire" il comando al posto del tuo dominio, ottenendo in tal modo il "codice di accoppiamento" che hai menzionato sopra. Ad esempio:
// OrderController
protected $orderRepository;
public function findOrder( int $orderId ) : ActionResult
{
$order = $this->orderRepository->find($orderId);
return $this->view('order', $order);
}
vs.
// OrderController
protected $orderService;
public function findOrder( int $orderId ) : ActionResult
{
$order = $this->orderSerivce->find($orderId);
return $this->view('order', $order);
}
Ora, questa può sembrare una sciocca differenza semantica in cui ho appena ribattezzato una singola variabile, ma illustra un concetto fondamentale e molto importante. Il tuo Controller
fa davvero parte del tuo Controllers
, non del tuo View
layer. Il primo esempio ha dipendenza tra Application
e Controller
tramite Domain
(rendendo la parte OrderRepository
del livello Controller
), dove il secondo esempio ha la dipendenza dal Application
tramite Application
invece (mantenendo OrderService
in Controller
).
Spingendo l'implementazione di trovare un View
"verso il basso" in un servizio di applicazione, noi stiamo ottenendo il disaccoppiamento. Il livello Order
dipende solo dall'interfaccia View
. Questa interfaccia esiste a un livello concettualmente inferiore al IOrderService
e può essere utilizzata da un numero qualsiasi di componenti (ad esempio un metodo che restituisce Controllers
in HTML e un metodo che restituisce Order
in JSON).
Il take-away importante di cui sopra è che il contratto (interfaccia) per la comunicazione tra i tuoi livelli concettuali dovrebbe essere definito in la tua applicazione. Questo facilita il riutilizzo tra Order
.
La mia ipotesi è che, al caricamento della pagina, ti piacerebbe renderizzare il più possibile lato server, ma non avere un layer Views
che aiuti a facilitare diversi Application
in modo da prevenire la duplicazione del codice o accoppiamento tra Views
. Ri-organizzare la tua applicazione può servire come soluzione.