Использование моего собственного API Laravel
Я разрабатываю приложение Laravel 4, которое сделает те же операции CRUD с моим набором данных доступными через API REST JSON и веб-интерфейс. Похоже, что для предотвращения нарушения принципа DRY, согласно которому мой пользовательский интерфейс должен использовать мой собственный API, перенаправляя все запросы из пользовательского интерфейса обратно в API. Я не уверен, однако, в том, как лучше всего подойти к этой работе. Предположительно, у меня были бы отдельные контроллеры пользовательского интерфейса и API, и я каким-то образом перенаправлял бы запросы. Или мне следует рассмотреть другой подход в целом?
Спасибо.
7 answers
На самом деле я работаю над той же идеей, и это довольно аккуратно. С Laravel у вас есть возможность делать внутренние запросы (некоторые могут называть это HMVC, но я не буду). Вот основы внутреннего запроса.
$request = Request::create('/api/users/1', 'GET');
$response = Route::dispatch($request);
$response
теперь будет содержать возвращенный ответ API. Обычно это будет возвращена строка в кодировке JSON, которая отлично подходит для клиентов, но не настолько хороша для внутреннего запроса API. Вам придется расширить здесь несколько вещей, но в основном идея заключается в том, чтобы вернуть фактический объект обратно для внутреннего вызова, а для внешних запросов вернуть отформатированный ответ JSON. Вы можете использовать такие вещи, как $response->getOriginalContent()
здесь для такого рода вещей.
Что вам следует сделать, так это создать своего рода внутренний Dispatcher
, который позволит вам отправлять запросы API и возвращать исходный объект. Диспетчер также должен обрабатывать неправильно сформированные запросы или неправильные ответы и создавать исключения для соответствия.
Сама идея основательна. Но планирование API - это тяжелая работа. Я бы рекомендовал вам составить хороший список всех ваших ожидаемых конечных точек и составить несколько версий API, а затем выбрать лучшую.
ПРИМЕЧАНИЕ: Как 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);
СООБЩЕНИЕ w/ файлы cookie
$request = Request::create('/api/users/1', 'POST', Input::get(), Cookie::get('name'));
$response = Route::dispatch($request);
СООБЩЕНИЕ с файлами
$request = Request::create('/api/users/1', 'POST', Input::get(), null, Input::file('file'));
$response = Route::dispatch($request);
Я надеюсь, что это поможет кому-то еще. Если вы не используете форму или используете, но не используете фасад ввода/файлов cookie Laravel, замените фасады ввода/файлов cookie своим собственным контентом.
Тейлор Отуэлл предложил использовать app()->handle()
вместо Route::dispatch()
для получения чистого запроса.
Для Route::dispatch($request)
Я заметил, что если конечная точка вашего запроса без GET (параметры в теле HTTP-запроса) использует введенную зависимость \Illuminate\Http\Request
или \Illuminate\Foundation\Http\FormRequest
расширяющий экземпляр, состояние параметров, файлы cookie, файлы и т. Д. Взяты из исходного HTTP-запроса. т.Е. Для метода действия контроллера вашего приложения.
Если имена параметров и тип метода публикации для вашего приложения контроллер и контроллер API одинаковы, вы не заметите разницы, так как передаются исходные значения параметров. Но когда вы вручную собираете 3-й параметр Request::create()
, Route::dispatch()
приведет к тому, что он будет проигнорирован.
app()->handle()
устраняет эту проблему контекста в жизненном цикле запроса Laravel.
Предостережение: app()->handle()
влияет на Illuminate\Support\Facades\Request
, обновляя его с помощью этого нового экземпляра запроса. В качестве побочного эффекта такие вызовы, как Request::isXmlHttpRequest()
или redirect()->back()
, вызываемые после app()->handle()
, вызовут непредсказуемое поведение. Я бы предложил отслеживать контекст вашего первоначального запроса и вместо этого использовать redirect()->to(route('...'))
, чтобы вы строго контролировали поток и состояние вашего приложения.
Учитывая все эти угловые случаи, возможно, лучше всего просто выполнить ручную завивку с помощью HTTP-клиента Guzzle.
Если вы используете свой собственный API, используйте app()->handle()
вместо Route::dispatch()
, как предложил Дерек Макдональд.
app()->handle()
создает новый запрос, в то время как Route::dispatch()
выполняет маршрут в стеке, эффективно игнорируя параметры, которые являются частью отправляемого вами запроса.
Редактировать: Просто предупреждение. Тейлор Отуэлл советует не использовать подзапросы для выполнения внутренних вызовов API, так как они портят текущий маршрут. Вы можете использовать клиент HTTP API, такой как Guzzle
, вместо того, чтобы вызовы API.
Вы можете использовать Потребитель API Optimus, API чистый и простой, пример выполнения внутреннего запроса:
$response = app()->make('apiconsumer')->post('/oauth/token', $data);
В своей основе он использует Illuminate\Routing\Router
и Illuminate\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));
Если вы хотите использовать api входа в систему passport внутренне, вам нужно добавить параметры в исходный запрос:
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();
}
Если вы хотите использовать api входа в систему passport внутренне, вам нужно добавить параметры в исходный запрос:
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();
}