Как сделать первое веб-приложение REST API в Laravel
Я хочу сделать первое приложение API в Laravel. Я не знаю, как лучше всего это сделать, я объясню, что я пытаюсь сделать, но, пожалуйста, не стесняйтесь давать ответы, как сделать это по-другому.
Я не хочу, чтобы весь мой интерфейс был написан в javascript и проанализировал вывод JSON API с помощью angular.js или чего-то подобного. Я хочу, чтобы приложение Laravel создавало HTML-представления. Я пытаюсь пойти по пути, имея два контроллера для API и один для Интернета. Для показа действия пользователя мои 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 User Controller
$response = $this->show($id);
return View::make('user.view')->with('data', $response->getData());
}
}
В WebUserController
я могу получить json-контент ответа с getData()
, но я не могу получить заголовки и код состояния (они являются защищенными свойствами Illuminate\Http\JsonResponse
).
Я думаю, что мой подход может быть не самым лучшим, поэтому я открыт для предложений, как сделать это приложение.
EDIT. На вопрос, как получить заголовки и статус ответа, ответил Дрю Льюис, но я все еще думаю, что может быть лучший способ, как это сделать
Ответы
Ответ 1
Вы должны использовать шаблон оформления репозитория/шлюза: см. ответы здесь.
Например, при работе с моделью пользователя сначала создайте репозиторий пользователей. Ответственность только репозитория пользователя заключается в том, чтобы связываться с базой данных (выполняя операции 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. Это так, что если вы измените ORM на нечто иное, чем красноречивое, вы можете просто изменить этого поставщика услуг и никаких других изменений в вашей кодовой базе не требуется:
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);
}
}
Наконец, создайте свой пользовательский веб-контроллер. Этот контроллер говорит с вашим User Gateway:
class UserController extends BaseController
{
public function __construct(UserGatway $userGateway)
{
$this->userGateway = $userGateway;
}
public function create()
{
$user = $this->userGateway->createUser(Input::all());
}
}
Структурируя дизайн вашего приложения таким образом, вы получаете несколько преимуществ: вы достигаете очень четкого разделения проблем, так как ваше приложение будет придерживаться Принцип единой ответственности (путем разделения вашей бизнес-логики на логику базы данных). Это позволяет вам выполнять тестирование модулей и интеграции гораздо проще, делает ваши контроллеры максимально возможными, а также позволяет вам легко заменять Eloquent для любой другой базы данных, если вы захотите в будущем.
Например, если вы изменяетесь с Eloquent на Mongo, единственное, что вам нужно изменить, это привязка поставщика услуг, а также создание MongoUserRepository, который реализует интерфейс UserRepository. Это связано с тем, что репозиторий - это только вещь, говорящая с вашей базой данных - она ничего не знает. Поэтому новый 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. Никаких других изменений не требуется.
Ответ 2
Для этого проекта вы должны использовать репозиторий.
Пример -
//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()));
}
}
Ответ 3
Оформить заказ Контроллеры Laravel RESTful:
http://laravel.com/docs/controllers#restful-controllers
Их документы выполняют довольно хорошую работу.
Но еще лучше этот урок:
http://code.tutsplus.com/tutorials/laravel-4-a-start-at-a-restful-api-updated--net-29785
Ответ 4
Это видео Джеффри Пути, он один из лучших разработчиков Laravel. В этом уроке он подключает приложение BackboneJS к службе RESTful, которую он устанавливает в Laravel. Тогда это не улучшится. Я могу написать вам много шаблонов, но просто изучите его, посмотрев хорошее видео и выпейте кофе.;)
https://www.youtube.com/watch?v=uykzCfu1RiQ
Ответ 5
У меня есть ответ на проблему, с которой вы сталкиваетесь с ответом.
Вы можете получить заголовки, код состояния и данные из ответа.
// 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();
Заголовки $response- > представляют собой Symfony\Component\HttpFoundation\ResponseHeaderBag, который наследуется от Symfony\Component\HttpFoundation\HeaderBag
Ответ 6
Я бы также рекомендовал использовать репозиторий.
Попытка вызвать один контроллер из другого будет падать в шаблон под названием HMVC (Hierarchical model-view-controller).
Это означает, что все ваше приложение опирается на более низкие модули.
В этом случае ваш API будет служить репозиторием для ваших данных (что не самое худшее в мире вначале).
Однако, когда вы затем изменяете структуру того, как данные возвращаются в вашем API, все остальное, опираясь на это, должно будет знать, как реагировать.
Скажите, что вы хотели иметь проверки авторизации, чтобы увидеть, сможет ли зарегистрированный пользователь увидеть детали возвращаемого пользователя и произошла ошибка.
В API вы вернете объект Response с 403 запрещенным кодом и некоторыми метаданными.
Ваш контроллер 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('/');
}
}
Это дает вам код многократного использования и позволяет вам самостоятельно менять реализацию вашего контроллера, не опасаясь изменить другое поведение.
Я написал больше о том, как реализовать шаблон репозитория в этот пост: вы можете игнорировать интерфейс и пропустить право на реализации, если хотите.