2014-04-16 74 views
27

我想在Laravel中創建一個API第一個應用程序。我不知道最佳做法是什麼,我會解釋我正在嘗試做什麼,但請隨時以不同的方式回答如何做到這一點。如何在Laravel中創建REST API第一個Web應用程序

我不希望我所有的前端都用javascript編寫,並用angular.js或類似的東西解析API的JSON輸出。我想讓我的Laravel應用程序生成HTML視圖。我正試圖走上兩個控制器,一個用於API,另一個用於Web。爲展示用戶操作我的routes.php文件是這樣的:

# the web controller 
Route::controller('user', 'WebUserController'); 

# the api controller 
Route::group(array('prefix' => 'api'), function() { 
    Route::resource('user', 'UserController'); 
}); 

所以/user會帶我去WebUserController/api/user會帶我去UserController。現在我想把我所有的邏輯放在API UserController中,並從WebUserController中調用它的動作。這是對他們倆的代碼:

class UserController extends BaseController 
{ 
    public function show($id) 
    { 
     $user = User::find($id); 
     return Response::json(array('success'=>true,'user'=>$user->toArray())); 
    } 
} 

class WebUserController extends UserController 
{ 
    public function getView($id) 
    { 
     # call the show method of the API's User Controller 
     $response = $this->show($id); 
     return View::make('user.view')->with('data', $response->getData()); 
    } 
} 

WebUserController我能夠獲得與getData()響應的JSON的內容,但我不能夠獲得頭和狀態碼(保護它們的屬性的Illuminate\Http\JsonResponse)。

我認爲我的方法可能不是最好的,所以我接受建議如何使這個應用程序。

編輯:現在的問題是如何讓頭和響應的狀態已經被Drew Lewis回答,但我仍然認爲,有可能是一個更好的方法如何設計這個

+0

馬丁你好,我有同樣的問題要在Laravel 5.1中解決。那麼,你是如何實施的?你有沒有使用Repositor模式? – Ashish

+0

@Ashish,當我問這個時,我和Nyan的答案一起去了。這似乎是最簡單的解決方案,並做了我所需要的。雖然我還沒有與Laraval 5.1合作,但不知道自那以後發生了什麼變化。 –

+0

您是否爲Web和API創建單獨的控制器,如果是的話,您是如何設法防止代碼重複的,我想知道存儲庫設計模式,我們只能將DB邏輯移出控制器 – Ashish

回答

38

你應該利用庫/網關設計模式:請參閱答案here

例如,在處理User模型時,首先創建一個User Repository。用戶知識庫的職責是與數據庫進行通信(執行CRUD操作)。只有。該用戶系統信息庫延伸的公共基礎信息庫,並實現包括所有您需要的方法的接口:

class EloquentUserRepository extends BaseRepository implements UserRepository 
{ 
    public function __construct(User $user) { 
     $this->user = $user; 
    } 


    public function all() { 
     return $this->user->all(); 
    } 

    public function get($id){} 

    public function create(array $data){} 

    public function update(array $data){} 

    public function delete($id){} 

    // Any other methods you need go here (getRecent, deleteWhere, etc) 

} 

然後,創建一個服務提供商,結合您的用戶庫界面,您的口才用戶庫。無論何時您需要用戶資源庫(通過IoC容器解析它或在構造函數中注入依賴項),Laravel都會自動爲您提供剛創建的Eloquent用戶資源庫的實例。這是這樣,如果你改變奧姆斯比雄辯其他的東西,你可以簡單地更改此服務提供商並沒有其他改變你的代碼是必需的:

use Illuminate\Support\ServiceProvider; 

class RepositoryServiceProvider extends ServiceProvider { 

    public function register() { 
     $this->app->bind(
      'lib\Repositories\UserRepository',  // Assuming you used these 
      'lib\Repositories\EloquentUserRepository' // namespaces 
     ); 
    } 

} 

接下來,創建一個用戶網關,誰的目的是與任意數量的存儲庫交談並執行應用程序的任何業務邏輯:

use lib\Repositories\UserRepository; 

class UserGateway { 

    protected $userRepository; 

    public function __construct(UserRepository $userRepository) { 
     $this->userRepository = $userRepository; 
    } 

     public function createUser(array $input) 
     { 
      // perform any sort of validation first 
      return $this->userRepository->create($input); 
     } 

} 

最後,創建您的用戶Web控制器。該控制器會談到你的用戶網關:

class UserController extends BaseController 
{ 
    public function __construct(UserGatway $userGateway) 
    { 
     $this->userGateway = $userGateway; 
    } 

    public function create() 
    { 
     $user = $this->userGateway->createUser(Input::all()); 

    } 
} 

通過構建這樣的應用程序的設計,你會得到幾個好處:你獲得的關注非常清晰的分離,因爲你的應用程序將秉承Single Responsibility Principle(通過將您的業務邏輯從數據庫邏輯中分離出來)。這使您能夠以更簡單的方式執行單元和集成測試,使您的控制器儘可能瘦,並且如果您將來願意,可以輕鬆更換任何其他數據庫的Eloquent。

例如,如果從Eloquent更改爲Mongo,則需要更改的唯一事情是服務提供者綁定以及創建實現UserRepository接口的MongoUserRepository。這是因爲存儲庫只是只有事情與您的數據庫交談 - 它不知道任何其他事情。因此,新MongoUserRepository可能看起來像:

class MongoUserRepository extends BaseRepository implements UserRepository 
{ 
    public function __construct(MongoUser $user) { 
     $this->user = $user; 
    } 


    public function all() { 
     // Retrieve all users from the mongo db 
    } 

    ... 

} 

和服務提供商現在的UserRepository接口綁定到新的MongoUserRepository:

$this->app->bind(
     'lib\Repositories\UserRepository',  
     'lib\Repositories\MongoUserRepository' 
); 

縱觀所有網關你一直在引用UserRepository,所以通過做出這個改變,你實際上告訴Laravel使用新的MongoUserRepository而不是舊的Eloquent。不需要其他更改。

+1

謝謝,這是一個比Nyan的答案更復雜的設計......你能解釋一下什麼是好處。例如,如果要更改另一個ORM的Eloquent,則需要更改EloquentUserRepository,但也需要更改所有網關。 –

+0

請重新閱讀我的答案 - 我添加了更多信息。如果更改爲另一個ORM,則不需要更改任何網關,只需更改服務提供商和存儲庫即可。 – seeARMS

+5

太多的鍋爐板,只是爲了不太可能改變ORM的情況。 – malhal

1

我要你與應對所遇到的問題的迴應。 您可以從Response中獲取標題,狀態碼和數據。

// your data 
$response->getData(); 

// the status code of the Response 
$response->getStatusCode(); 

// array of headers 
$response->headers->all(); 

// array of headers with preserved case 
$response->headers->allPreserveCase(); 

$響應 - >頭是Symfony的\分量\ HttpFoundation \ ResponseHeaderBag從Symfony的\組件將繼承\ HttpFoundation \ HeaderBag

+0

耶,提取所有我需要的東西。一般情況下怎麼樣......你能想出一個更好的主意嗎? –

+0

@馬丁im想法的方式,只有一個控制器的兩個。爲響應構建數據並將其傳遞給基於它是否來自api路由的中間方將返回正確的響應。但它取決於你期望Api @ show與Web @ getView在數據方面有多不同。 – lagbox

7

你應該使用存儲庫這樣的設計。

示例 -

//UserRepository Class 
class UserRepository { 
    public function getById($id) 
    { 
     return User::find($id); 
    } 
} 

// WebUser Controller 
class WebUserController extends BaseController { 
    protected $user; 

    public function __construct(UserRepository $user) 
    { 
     $this->user = $user; 
    } 

    public function show($id) 
    { 
     return View::make('user.view')->with('data', $this->user->getById($id)); 
    } 
} 

// APIUser Controller 
class UserController extends BaseController { 
    protected $user; 

    public function __construct(UserRepository $user) 
    { 
     $this->user = $user; 
    } 

    public function show($id) 
    { 
     $data =>$this->user->getById($id); 
     return Response::json(array('success'=>true,'user'= $data->toArray())); 
    } 
} 
+1

這看起來很好,很簡單,每個型號只有一個額外的類。 –

2

這是Jeffrey Way的視頻,他是Laravel更好的開發者之一。在本教程中,他將BackboneJS應用程序連接到他在Laravel中設置的RESTful服務。這沒有比這更好。我可以給你寫很多樣板,但只需通過觀看漂亮的視頻和喝咖啡來學習。 ;)

https://www.youtube.com/watch?v=uykzCfu1RiQ

+0

嗯,這個似乎展示瞭如何在laravel中創建一個後端json api,並且在骨幹中有一個前端,這並不是我正在尋找的。 –

+0

只需使用json_decode(),你有一個php數組,並忽略它的BackboneJS。它是RESTful的,所以調用API無關緊要。它返回JSON的事實很棒,因爲任何語言都可以處理JSON! – sidneydobber

+0

我沒有看到讓Laravel將PHP數組轉換爲JSON字符串,然後在您自己的代碼中手動解碼它。 –

1

我也建議使用一個倉庫。 試圖從另一個控制器調用另一個控制器會落入稱爲HMVC(分層模型 - 視圖 - 控制器)的模式。 這意味着您的整個應用程序依賴於較低的模塊。 在這種情況下,您的API將作爲您的數據存儲庫(這不是世界上最糟糕的事情)。

但是,當您修改API中的數據返回結構時,其他所有依賴於它的結構都必須知道如何響應。 假設你想進行授權檢查,看看登錄的用戶是否應該能夠看到返回用戶的詳細信息,並且出現錯誤。

在API中,您將返回一個包含403禁止代碼和一些元數據的Response對象。 您的HTML控制器必須知道如何處理這個問題。

將此對比於可能引發異常的存儲庫。

public function findById ($id) 
{ 
    $user = User::findOrFail($id); 

    if (Auth::user->hasAccessTo($user)) { 
     return $user; 
    } else { 
     throw new UnauthorizedAccessException('you do not have sufficient access to this resource'); 
    } 
} 

而且你的API控制器看起來更像是這樣的:那麼

public function show($id) 
{ 
    try { 
     return $this->user->findById($id); 
    } catch (UnauthorizedAccessException $e) { 
     $message = $e->getMessage(); 
     return Response::json('403', ['meta' => ['message' => $message]])); 
    } 
} 

你的HTML控制器是這樣的:

public function show($id) 
{ 
    try { 
     $user = $this->user->findById($id); 
    } catch (UnauthorizedAccessException $e) { 
     Session::flash('error', $e->getMessage()); 
     // Redirect wherever you would like 
     return Response::redirect('/'); 
    } 
} 

這讓你很可重用的代碼,並讓你改變您的控制器實現獨立,無需擔心改變其他人的行爲。 我寫了關於如何在this post中實現存儲庫模式的更多信息:如果您願意,可以忽略該接口並跳過實現。

相關問題