2013-05-13 73 views
46

我正在开发一个Laravel 4应用程序,它将通过JSON REST API和Web UI对我的数据集进行相同的CRUD操作。看起来,为了防止打破DRY原则,我的UI应该通过将所有请求从UI返回给API来使用我自己的API。尽管如此,我仍然不确定如何做这项工作的最佳方法。据推测,我会分开UI和API控制器,并以某种方式路由请求。或者我应该完全看待不同的方法?消费我自己的Laravel API

谢谢。

回答

37

我实际上正在修改相同的想法,它非常整齐。有了Laravel,你确实有能力提出内部请求(有些人可能将此称为HMVC,但我不会)。以下是内部请求的基础知识。

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

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

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

你应该看看做的是构造某种内部Dispatcher,它允许你调度API请求并返回原始对象。调度员还应该处理格式错误的请求或不良响应,并抛出异常匹配。

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

+1

有趣的是,我在找这方面的文档,最初找不到任何。意识到这实际上是从Symfony继承的 – robjmills 2013-05-14 10:05:07

+0

是的创建初始请求是通过Symfony'HttpFoundation'组件完成的,但是请求的分派是由路由器完成的。 – 2013-05-14 10:19:21

+0

你提到“原始对象”,你在这里指的是什么? – robjmills 2013-05-14 10:49:21

20

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

我目前正在做同样的事情,贾森的回答让我朝着一个很好的方向前进。看着Symfony\Component\HttpFoundation\Request文档,我想出了如何POST,以及我需要做的一切。您使用的是形式假设,这里是一些代码,可以帮助你:

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瓦特/饼干

$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); 

我希望这可以帮助别人。如果您没有使用表单,或者您没有使用Laravel的Input/Cookie外观,请用您自己的内容替换Input/Cookie外观。

+0

完美,谢谢! – Ulterior 2014-09-23 21:49:49

+2

我所看到的唯一问题就是没有调用路由过滤器。 – vcardillo 2015-01-24 18:44:50

+0

链接中断,更新:http://api.symfony.com/master/Symfony/Component/HttpFoundation/Request.html – 2016-01-18 07:54:26

10

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

对于Route::dispatch($request)我注意到,如果你的非GET请求的终点(在HTTP请求的身体参数)使用依赖注入\Illuminate\Http\Request\Illuminate\Foundation\Http\FormRequest延长例如,参数,饼干,文件等的状态是从原始 HTTP请求。即为您的应用程序的控制器操作方法。

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

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

注意:app()->handle()影响Illuminate\Support\Facades\Request,使用这个新的请求实例刷新它。作为连锁效应,在app()->handle()之后调用Request::isXmlHttpRequest()redirect()->back()等调用将导致不可预知的行为。我建议跟踪原始请求的上下文,并改为使用redirect()->to(route('...')),以便严格控制应用的流量和状态。

鉴于所有这些情况,最好使用Guzzle HTTP client进行手动卷曲。

0

您可以使用Optimus API consumer,API是干净和简单,例如使内部请求:在它的核心,它采用Illuminate\Routing\RouterIlluminate\Http\Request拨打电话

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

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

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

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

app()->handle()创建一个新的请求,而Route::dispatch()在堆栈内运行路由,有效地忽略了参数,这些参数是您要发送的请求的一部分。

编辑:只是单挑。泰勒Otwell advises against using sub-requests to make internal API calls, as they mess the current route。您可以使用HTTP API客户端(例如Guzzle)来进行API调用。

0

如果您正在寻找内部使用护照登录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

如果您正在寻找内部使用护照登录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(); 
}