2013-05-13 7 views
46

Ich entwickle eine Laravel 4-App, die dieselben CRUD-Operationen für meine Datenmenge über eine JSON-REST-API und eine Web-UI bereitstellt. Es scheint, dass, um das DRY-Prinzip zu brechen, dass meine Benutzeroberfläche meine eigene API konsumieren sollte, indem alle Anfragen von der Benutzeroberfläche zurück an die API geleitet werden. Ich bin mir jedoch nicht sicher, wie diese Arbeit am besten funktioniert. Vermutlich hätte ich separate UI- und API-Controller und würde die Anfragen irgendwie weiterleiten. Oder sollte ich insgesamt einen anderen Ansatz wählen?Meine eigene Laravel-API verwenden

Danke.

Antwort

37

Ich bin eigentlich mit der gleichen Idee basteln und es ist ziemlich ordentlich. Mit Laravel haben Sie die Möglichkeit, interne Anfragen zu stellen (einige mögen dies als HMVC bezeichnen, aber ich werde es nicht tun). Hier sind die Grundlagen einer internen Anfrage.

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

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

$response wird nun enthalten die zurückgegebene Antwort des API. In der Regel wird eine JSON-codierte Zeichenfolge zurückgegeben, die für Clients sehr nützlich ist, aber für eine interne API-Anfrage nicht besonders geeignet ist. Sie müssen hier ein paar Dinge erweitern, aber im Grunde geht es darum, das eigentliche Objekt für den internen Aufruf zurückzugeben und bei externen Anforderungen die formatierte JSON-Antwort zurückzugeben. Sie können Dinge wie $response->getOriginalContent() hier für diese Art von Sache verwenden.

Worauf Sie achten sollten, ist das Erstellen einer Art von internem Dispatcher, mit dem Sie API-Anfragen senden und das ursprüngliche Objekt zurückgeben können. Der Dispatcher sollte auch fehlerhafte Anfragen oder ungültige Antworten behandeln und Ausnahmen zur Übereinstimmung bringen.

Die Idee selbst ist solide. Aber die Planung einer API ist harte Arbeit. Ich würde Ihnen empfehlen, eine gute Liste aller erwarteten Endpunkte aufzuschreiben und ein paar API-Versionen zu entwerfen und dann die beste auszuwählen.

+1

Interessant, ich wurde für die Dokumentation zu diesem Thema suchen und nicht am Anfang finden. Realisiert, dass dies tatsächlich von Symfony geerbt wird. – robjmills

+0

Ja, das Erstellen der ersten Anfrage läuft durch die Symfony 'HttpFoundation' Komponente, aber die Verteilung der Anfrage erfolgt durch den Router. –

+0

Sie erwähnen "Originalobjekt", was meinen Sie eigentlich hier? – robjmills

20

HINWEIS: Da vcardillo unten angegeben ist, werden Routenfilter nicht mit diesen Methoden aufgerufen.

Ich mache gerade das gleiche, und Jasons Antwort brachte mich in eine gute Richtung. Mit Blick auf die Dokumentation Symfony\Component\HttpFoundation\Request, ich habe herausgefunden, wie man POST, sowie alles, was ich sonst tun müsste. Angenommen, Sie ein Formular verwenden, hier ist ein Code, der Ihnen helfen könnten:

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/Cookies

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

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

POST mit Dateien

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

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

Ich hoffe, das hilft jemand anderem. Wenn Sie kein Formular verwenden oder Laravels Input/Cookie-Fassade nicht verwenden, ersetzen Sie die Input/Cookie-Fassaden durch Ihre eigenen Inhalte.

+0

perfekt, danke! – Ulterior

+2

Das einzige Problem, das ich bei all diesen gesehen habe, ist, dass Routenfilter nicht aufgerufen werden. – vcardillo

+0

Link unterbrochen, Aktualisierung: http://api.symfony.com/master/Symfony/Component/HttpFoundation/Request.html –

10

Taylor Otwell suggested mit app()->handle() anstatt Route::dispatch(), um eine saubere Anfrage zu erreichen.

Für Route::dispatch($request) bemerkte ich, wenn der Endpunkt Ihrer Nicht-GET-Anforderung (Parameter auf dem HTTP-Request-Bodys) verwendet eine Abhängigkeit injiziert \Illuminate\Http\Request oder \Illuminate\Foundation\Http\FormRequest Instanz erstreckt, Zustand der Parameter, Cookies, Dateien usw. sind von der Original HTTP-Anfrage. d.h. für die Controller-Aktionsmethode Ihrer Anwendung.

Wenn die Parameternamen und der Post-Methodentyp für Ihren App-Controller und API-Controller identisch sind, werden Sie den Unterschied nicht bemerken, da die ursprünglichen Parameterwerte weitergegeben werden. Wenn Sie jedoch den 3. Parameter Request::create() manuell zusammensetzen, wird Route::dispatch() dazu führen, dass er ignoriert wird.

app()->handle() behebt dieses Kontextproblem im Laravel-Anforderungslebenszyklus.

Caveat:app()->handle() wirkt Illuminate\Support\Facades\Request, es mit dieser neuen Anforderungsinstanz zu aktualisieren. Als Folgeeffekt führen Aufrufe wie Request::isXmlHttpRequest() oder redirect()->back(), die nach app()->handle() aufgerufen werden, zu unvorhersehbarem Verhalten. Ich würde vorschlagen, den Kontext Ihrer ursprünglichen Anfrage zu verfolgen und stattdessen redirect()->to(route('...')) zu verwenden, damit Sie den Fluss und den Status Ihrer App genau kontrollieren.

Angesichts all dieser Ecken Fälle kann es am besten sein, nur eine manuelle Curl mit einem Guzzle HTTP client zu tun.

0

Sie Optimus API consumer verwenden können, ist die API sauber und einfach, beispielsweise einen internen antrag:

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

Darin Kern ist es Illuminate\Routing\Router und Illuminate\Http\Request nutzt den Anruf zu tätig

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

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

Wenn Sie verbrauchen Ihre eigene API, verwenden Sie app()->handle() anstelle von Route::dispatch(), wie Derek MacDonald vorgeschlagen hat.

app()->handle() erstellt eine neue Anforderung, während Route::dispatch() die Route innerhalb des Stapels ausführt und Parameter, die Teil der gesendeten Anforderung sind, ignoriert.

Bearbeiten: Nur ein Heads-up. Taylor Otwell advises against using sub-requests to make internal API calls, as they mess the current route. Sie können stattdessen einen HTTP-API-Client wie Guzzle verwenden, um API-Aufrufe auszuführen.

0

Wenn Sie intern für die Verwendung von Pass Login api suchen, dann müssen Sie die Parameter ursprüngliche Anforderung hinzuzufügen:

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

Wenn Sie intern für die Verwendung von Pass Login api suchen, dann müssen Sie die hinzufügen Parameter zur ursprünglichen Anfrage:

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(); 
}