2013-05-13 10 views
46

Sto sviluppando un'applicazione Laravel 4 che renderà le stesse operazioni CRUD sul mio set di dati disponibili tramite un'API JSON REST e un'interfaccia utente web. Sembra che per evitare di infrangere il principio DRY che la mia UI debba consumare la mia API instradando tutte le richieste dall'interfaccia utente all'API. Non sono sicuro però del miglior approccio per fare questo lavoro. Presumibilmente avrei controller UI e API separati e in qualche modo indirizzare le richieste attraverso. O dovrei guardare ad un approccio diverso del tutto?Consumare la mia API Laravel

Grazie.

risposta

37

In realtà sto armeggiando con la stessa idea ed è abbastanza pulito. Con Laravel hai la possibilità di fare richieste interne (alcuni potrebbero riferirsi a questo come HMVC, ma non lo farò). Ecco le basi di una richiesta interna.

$request = Request::create('/api/users/1', 'GET'); 

$response = Route::dispatch($request); 

$response conterrà ora la risposta restituita delle API. In genere, viene restituita una stringa codificata JSON che è ottima per i client, ma non eccezionale per una richiesta API interna. Dovrai estendere alcune cose qui, ma fondamentalmente l'idea è di restituire l'oggetto reale per la chiamata interna, e per le richieste esterne restituire la risposta JSON formattata. Puoi fare uso di cose come $response->getOriginalContent() qui per questo genere di cose.

Quello che dovresti fare è costruire una sorta di interno Dispatcher che ti permette di inviare richieste API e restituire l'oggetto originale. Il dispatcher deve anche gestire richieste malformate o risposte errate e generare eccezioni per combaciare.

L'idea è solida. Ma pianificare un'API è un duro lavoro. Ti consigliamo di scrivere un buon elenco di tutti i tuoi endpoint attesi e di redigere un paio di versioni API, quindi selezionare il migliore.

+1

Interessante, stavo cercando la documentazione su questo e non ho potuto trovare nessuno inizialmente. Realizzato questo è in realtà ereditato da Symfony – robjmills

+0

Sì, la creazione della richiesta iniziale passa attraverso il componente 'HttpFoundation' di Symfony, ma l'invio della richiesta viene eseguito dal router. –

+0

hai menzionato "oggetto originale", a cosa ti stai riferendo in questo caso? – robjmills

20

NOTA: come evidenziato dal vcardillo di seguito, i filtri di instradamento non vengono chiamati con questi metodi.

Attualmente sto facendo la stessa cosa, e la risposta di Jason mi ha fatto andare in una direzione fantastica. Guardando la documentazione di Symfony\Component\HttpFoundation\Request, ho scoperto come eseguire il POST, oltre a tutto ciò che avrei dovuto fare. Supponendo che si sta utilizzando un modulo, qui è un codice che potrebbe aiutare:

GET:

$request = Request::create('/api/users/1', 'GET'); 

$response = Route::dispatch($request); 

POST:

$request = Request::create('/api/users/1', 'POST', Input::get()); 

$response = Route::dispatch($request); 

POST w/biscotti

$request = Request::create('/api/users/1', 'POST', Input::get(), Cookie::get('name')); 

$response = Route::dispatch($request); 

POST w/files

$request = Request::create('/api/users/1', 'POST', Input::get(), null, Input::file('file')); 

$response = Route::dispatch($request); 

Spero che questo aiuti qualcun altro. Se non si sta utilizzando un modulo o si sta utilizzando la facciata Input/Cookie di Laravel, sostituire le facciate Input/Cookie con il proprio contenuto.

+0

perfetto, grazie! – Ulterior

+2

L'unico problema che ho riscontrato con tutti questi, è che i filtri di route non vengono chiamati. – vcardillo

+0

Collegamento interrotto, aggiornamento: http://api.symfony.com/master/Symfony/Component/HttpFoundation/Request.html –

10

Taylor Otwell suggested utilizzando app()->handle() anziché Route::dispatch() per ottenere una richiesta pulita.

Per Route::dispatch($request) ho notato se l'endpoint della tua richiesta non GET (parametri sul corpo della richiesta HTTP) utilizza una dipendenza iniettato \Illuminate\Http\Request o \Illuminate\Foundation\Http\FormRequest estendendo esempio, lo stato dei parametri, i cookie, file, ecc provengono dal originale richiesta HTTP. Ad esempio, per il metodo di azione del controller dell'applicazione.

Se i nomi dei parametri e il tipo di metodo post per il controller dell'app e il controller API sono uguali, non si noterà la differenza poiché i valori dei parametri originali vengono passati. Ma quando stai assemblando manualmente il 3 ° parametro di Request::create(), Route::dispatch(), verrà ignorato.

app()->handle() corregge tale problema di contesto nel ciclo di vita delle richieste di Laravel.

Avvertenza:app()->handle() interessa Illuminate\Support\Facades\Request, aggiornandolo con questa nuova istanza di richiesta. Come effetto a catena, chiamate come Request::isXmlHttpRequest() o redirect()->back() invocate dopo app()->handle() causeranno un comportamento imprevedibile. Ti suggerisco di tracciare il contesto della tua richiesta originale e utilizzare invece redirect()->to(route('...')) in modo da controllare rigorosamente il flusso e lo stato della tua app.

Dato tutti questi casi angolari, potrebbe essere meglio fare un arricciamento manuale utilizzando uno Guzzle HTTP client.

0

È possibile utilizzare Optimus API consumer, l'API è pulito e semplice, ad esempio facendo una richiesta interna:

$response = app()->make('apiconsumer')->post('/oauth/token', $data); 

Nel suo centro, utilizza Illuminate\Routing\Router e Illuminate\Http\Request per effettuare la chiamata

// create the request 
$this->request->create($uri, $method, $data, [], [], $server, $content); 

// get the response 
$response = $this->router->prepareResponse($request, $this->app->handle($request)); 
1

Se stai consumando la tua API, usa app()->handle() invece di Route::dispatch() come suggerito da Derek MacDonald.

app()->handle() crea una nuova richiesta, mentre Route::dispatch() esegue il percorso all'interno dello stack, ignorando efficacemente i parametri che fanno parte della richiesta che si sta inviando.

Modifica: solo un avviso. Taylor Otwell advises against using sub-requests to make internal API calls, as they mess the current route. Puoi invece utilizzare un client API HTTP come Guzzle per effettuare le chiamate API.

0

Se siete alla ricerca di utilizzare il passaporto login api internamente, allora avete bisogno di aggiungere i parametri alla richiesta iniziale:

protected function manualLogin(Request $request) 
{ 
    $email = $request->input('email'); 
    $password = $request->input('password'); 

    $request->request->add([ 
     'username' => $email, 
     'password' => $password, 
     'grant_type' => 'password', 
     'client_id' => $clientID, 
     'client_secret' => $clientSecret, 
     'scope' => '*']); 

    $newRequest = Request::create('/oauth/token', 'post'); 

    return Route::dispatch($newRequest)->getContent(); 
} 
0

Se siete alla ricerca di utilizzare il passaporto login api internamente, allora avete bisogno di aggiungere il parametri alla richiesta originale:

protected function manualLogin(Request $request) 
    { 
     $email = $request->input('email'); 
     $password = $request->input('password'); 

     $request->request->add([ 
     'username' => $email, 
     'password' => $password, 
     'grant_type' => 'password', 
     'client_id' => $clientID, 
     'client_secret' => $clientSecret, 
     'scope' => '*']); 

    $newRequest = Request::create('/oauth/token', 'post'); 

    return Route::dispatch($newRequest)->getContent(); 
} 
Problemi correlati