web-dev-qa-db-ja.com

自分のLaravel APIを消費

JSON Laravel APIとWeb UIを介してデータセットで同じCRUD操作を使用できるようにするREST 4アプリを開発しています。 DRY UIからAPIにすべてのリクエストをルーティングすることで自分のAPIが消費するという原則を破るのを防ぐため。この作業を行うための最良のアプローチについては確信が持てません。 UIコントローラーとAPIコントローラーを別々にして、リクエストを何らかの方法でルーティングしますが、まったく別のアプローチを検討する必要がありますか?

ありがとう。

52
robjmills

私は実際に同じアイデアをいじくり回していて、それはかなりきれいです。 Laravelを使用すると、内部リクエストを行うことができます(これをHMVCと呼ぶこともありますが、私はしません)。内部リクエストの基本は次のとおりです。

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

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

_$response_には、返されたAPIの応答が含まれるようになりました。通常、これはクライアントに適したJSONエンコードされた文字列として返されますが、内部APIリクエストには適していません。ここではいくつかのことを拡張する必要がありますが、基本的には、内部呼び出しに対して実際のオブジェクトを返し、外部要求に対してはフォーマットされたJSON応答を返すという考え方です。このようなことのために、ここで$response->getOriginalContent()のようなものを利用できます。

行うべきことは、APIリクエストをディスパッチして元のオブジェクトを返すことができる、何らかの内部Dispatcherを構築することです。ディスパッチャは、不正な形式のリクエストまたは不正な応答も処理し、一致する例外をスローする必要があります。

アイデア自体は堅実です。しかし、APIの計画は大変な作業です。予想されるすべてのエンドポイントの適切なリストを作成し、いくつかのAPIバージョンをドラフトしてから、最適なものを選択することをお勧めします。

48
Jason Lewis

注:vcardilloが以下で指摘したように、これらのメソッドではルートフィルターは呼び出されません。

私は現在同じことをやっており、ジェイソンの答えは私を素晴らしい方向に導いてくれました。 Symfony\Component\HttpFoundation\Request のドキュメントを見て、POSTの方法と、他に必要なことをすべて理解しました。フォームを使用していると仮定すると、次のコードが役立ちます。

取得する:

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

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

役職:

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

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

Cookie付きのPOST

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

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

ファイル付きのPOST

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

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

これが他の人に役立つことを願っています。フォームを使用していない場合、またはLaravelのInput/Cookieファサードを使用していない場合は、Input/Cookieファサードを独自のコンテンツに置き換えます。

25
Domenic Fiore

Taylor Otwell 提案app()->handle()ではなくRoute::dispatch()を使用して、クリーンなリクエストを達成します。

Route::dispatch($request)の場合、GET以外のリクエストのエンドポイント(HTTPリクエスト本文のパラメーター)が\Illuminate\Http\Requestまたは\Illuminate\Foundation\Http\FormRequest拡張インスタンス、パラメーターの状態、Cookieを挿入した依存関係を使用していることに気付きました、ファイルなどはoriginalHTTPリクエストからのものです。つまり、アプリケーションのコントローラーアクションメソッド用です。

アプリコントローラーとAPIコントローラーのパラメーター名とpostメソッドタイプが同じ場合、元のパラメーター値が渡されるため、違いに気付かないでしょう。しかし、Request::create()の3番目のパラメーターを手動で組み立てている場合、Route::dispatch()は無視されます。

app()->handle()は、Laravelリクエストライフサイクルのコンテキスト問題を修正します。

警告:app()->handle()Illuminate\Support\Facades\Requestに影響し、この新しいリクエストインスタンスで更新します。ノックオン効果として、Request::isXmlHttpRequest()redirect()->back()のような呼び出しをapp()->handle()の後に呼び出すと、予測できない動作が発生します。元のリクエストのコンテキストを追跡し、代わりにredirect()->to(route('...'))を使用することをお勧めします。これにより、アプリのフローと状態を厳密に制御できます。

これらのすべてのコーナーケースを考えると、 Guzzle HTTPクライアント を使用して手動でカールを行うのが最善かもしれません。

14
Derek MacDonald

独自のAPIを使用している場合は、Derek MacDonaldが提案したように、app()->handle()の代わりにRoute::dispatch()を使用してください。

app()->handle()は新しいリクエストを作成し、Route::dispatch()はスタック内でルートを実行し、送信するリクエストの一部であるパラメーターを事実上無視します。

Edit:ただヘッドアップ。 Taylor Otwell サブリクエストを使用して内部API呼び出しを行うことをお勧めします。現在のルートを混乱させるため 。代わりにGuzzleのようなHTTP APIクライアントを使用して、API呼び出しを行うことができます。

3
jpcaparas

Optimus API consumer を使用できます。APIはクリーンでシンプルで、内部リクエストを作成する例です。

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

コアでは、Illuminate\Routing\RouterおよびIlluminate\Http\Request発信する

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

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

内部でパスポートログインAPIを使用する場合は、元のリクエストにパラメーターを追加する必要があります。

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

内部でパスポートログインAPIを使用する場合は、元のリクエストにパラメーターを追加する必要があります。

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
Pankaj Garg