2013-05-13 20 views
46

Я разрабатываю приложение Laravel 4, которое будет выполнять те же операции CRUD в моем наборе данных, доступные через API JSON REST и веб-интерфейс. Похоже, что для предотвращения нарушения принципа DRY мой пользовательский интерфейс должен использовать собственный API, перенаправляя все запросы из интерфейса пользователя обратно в API. Я не уверен, что об оптимальном подходе к этой работе. Предположительно, у меня были бы отдельные контроллеры пользовательского интерфейса и API и как-то маршрутизировать запросы. Или я должен вообще искать другой подход?Использование моего собственного API Laravel

Спасибо.

ответ

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

+0

Да, первоначальный запрос проходит через компонент Symfony 'HttpFoundation', но отправка запроса выполняется маршрутизатором. –

+0

Вы упоминаете «оригинальный объект», что вы на самом деле имеете в виду здесь? – robjmills

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 с файлами

$request = Request::create('/api/users/1', 'POST', Input::get(), null, Input::file('file')); 

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

Я надеюсь, что это поможет кому-то еще. Если вы не используете форму или используете, но не используете фасад Input/Cookie Laravel, замените фасады Input/Cookie своим собственным контентом.

+0

отлично, спасибо! – Ulterior

+2

Единственная проблема, которую я видел со всеми этими, заключается в том, что фильтры маршрутов не вызываются. – vcardillo

+0

Ссылка сломана, обновление: http://api.symfony.com/master/Symfony/Component/HttpFoundation/Request.html –

10

Taylor Otwell suggested используя app()->handle(), а не Route::dispatch() для достижения чистого запроса.

Для Route::dispatch($request) я заметил, если конечная точка вашего запроса, не GET (параметры на теле запроса HTTP) использует зависимость впрыскивается \Illuminate\Http\Request или \Illuminate\Foundation\Http\FormRequest расширения экземпляра, состояние параметров, печенье, файлы и т.д., находятся в оригинал 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('...')), чтобы вы строго контролировали поток и состояние вашего приложения.

Учитывая все эти угловые случаи, может быть лучше всего сделать ручное завивание, используя Guzzle HTTP client.

0

Вы можете использовать Optimus API consumer, то 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)); 
1

Если вы потребляете свой собственный API, используйте app()->handle() вместо Route::dispatch(), как предложил Дерек Макдональд.

app()->handle() создает новый запрос, а Route::dispatch() выполняет маршрут внутри стека, эффективно игнорируя параметры, которые являются частью отправляемого запроса.

Редактировать: Просто хедз-ап. Тейлор Отуэлл advises against using sub-requests to make internal API calls, as they mess the current route. Вы можете использовать HTTP API-клиент, например, Guzzle, чтобы совершать вызовы API.

0

Если вы ищете для использования паспорта для входа апи внутри, то вам необходимо добавить параметры исходного запроса:

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

Если вы ищете для использования паспорта для входа апи внутри, то вам необходимо добавить параметры к исходному запросу:

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(); 
} 
Смежные вопросы