Подтвердить что ты не робот

Как сделать первое веб-приложение 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. На вопрос, как получить заголовки и статус ответа, ответил Дрю Льюис, но я все еще думаю, что может быть лучший способ, как это сделать

4b9b3361

Ответ 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()));
    }
}

Ответ 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('/');
    }
}

Это дает вам код многократного использования и позволяет вам самостоятельно менять реализацию вашего контроллера, не опасаясь изменить другое поведение. Я написал больше о том, как реализовать шаблон репозитория в этот пост: вы можете игнорировать интерфейс и пропустить право на реализации, если хотите.