61

我正在开发一个 Laravel 4 应用程序,它将通过 JSON REST API 和 Web UI 对我的数据集进行相同的 CRUD 操作。似乎为了防止违反 DRY 原则,我的 UI 应该通过将所有请求从 UI 路由回 API 来使用我自己的 API。虽然我不确定完成这项工作的最佳方法。大概我会有单独的 UI 和 API 控制器,并以某种方式路由请求。还是我应该完全寻找一种不同的方法?

4

6 回答 6

62

我实际上正在修改相同的想法,而且非常简洁。使用 Laravel,您确实可以发出内部请求(有些人可能将其称为 HMVC,但我不会)。这是内部请求的基础知识。

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

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

$response现在将包含 API 返回的响应。通常这将返回一个 JSON 编码的字符串,这对客户端来说非常有用,但对于内部 API 请求来说不是那么好。您必须在这里扩展一些东西,但基本上想法是通过内部调用返回实际对象,而外部请求返回格式化的 JSON 响应。你可以利用$response->getOriginalContent()这里的东西来做这种事情。

您应该关注的是构建某种内部结构Dispatcher,允许您分派 API 请求并返回原始对象。调度程序还应处理格式错误的请求或错误响应并抛出异常以匹配。

这个想法本身是可靠的。但是规划 API 是一项艰巨的工作。我建议你写一个所有预期端点的好列表,并起草几个 API 版本,然后选择最好的一个。

于 2013-05-14T00:37:19.867 回答
33

注意:正如 vcardillo 在下面指出的,这些方法不会调用路由过滤器。

我目前正在做同样的事情,杰森的回答让我朝着一个很好的方向前进。查看Symfony\Component\HttpFoundation\Request文档,我知道了如何发布,以及我需要做的所有其他事情。假设您使用的是表单,这里有一些可以帮助您的代码:

得到:

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

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

邮政:

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

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

POST 带 cookie

$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 门面替换为你自己的内容。

于 2014-03-18T23:36:40.087 回答
19

Taylor Otwell建议使用app()->handle()而不是Route::dispatch()实现一个干净的请求。

因为Route::dispatch($request)我注意到如果您的非 GET 请求的端点(HTTP 请求正文上的参数)使用依赖注入\Illuminate\Http\Request\Illuminate\Foundation\Http\FormRequest扩展实例,则参数、cookie、文件等的状态来自原始HTTP 请求。即,对于您的应用程序的控制器操作方法。

如果您的应用控制器和 API 控制器的参数名称和 post 方法类型相同,您将不会注意到差异,因为原始参数值被传递。但是当您手动组装 , 的第三个参数时Request::create()Route::dispatch()将导致它被忽略。

app()->handle()修复了 Laravel 请求生命周期中的上下文问题。

警告: app()->handle()影响 Illuminate\Support\Facades\Request,用这个新的请求实例刷新它。作为连锁效应,like调用Request::isXmlHttpRequest()redirect()->back()调用 afterapp()->handle()将导致不可预知的行为。我建议跟踪您的原始请求的上下文,而不是使用redirect()->to(route('...')),以便您严格控制应用程序的流程和状态。

考虑到所有这些极端情况,最好只使用Guzzle HTTP 客户端进行手动卷曲。

于 2015-12-01T21:57:11.040 回答
7

如果您正在寻找内部使用护照登录 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();
}
于 2017-10-17T08:59:01.213 回答
4

如果您使用自己的 API,请使用app()->handle()而不是Route::dispatch()Derek MacDonald 建议的那样。

app()->handle()创建一个新请求,同时Route::dispatch()在堆栈中运行路由,有效地忽略作为您发送的请求的一部分的参数。

编辑:只是一个提示。Taylor Otwell建议不要使用子请求进行内部 API 调用,因为它们会弄乱当前路由。您可以改为使用 HTTP API 客户端Guzzle来进行 API 调用。

于 2017-06-30T03:56:09.943 回答
1

您可以使用Optimus API consumer,API 简洁明了,例如发出内部请求:

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

在它的核心中,它使用Illuminate\Routing\RouterIlluminate\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));
于 2017-05-26T18:55:58.130 回答