Использование моего собственного Laravel API

43

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

Спасибо.

Теги:
rest
laravel-4

7 ответов

38
Лучший ответ

Я действительно занимаюсь той же идеей, и это довольно аккуратно. С 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
  • 0
    Да, создание начального запроса проходит через компонент Symfony HttpFoundation , но отправка запроса выполняется маршрутизатором.
Показать ещё 9 комментариев
19

ПРИМЕЧАНИЕ. Как указал 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 с файлами cookie

$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);

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

  • 0
    отлично, спасибо!
  • 2
    Единственная проблема, с которой я столкнулся, это то, что фильтры маршрутов не вызываются.
Показать ещё 1 комментарий
8

Тейлор Отуэлл предложил, используя 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('...')), чтобы вы строго контролировали поток и состояние вашего приложения.

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

  • 0
    Жрет HTTP почему-то зависает приложение при выполнении php artisan serve (работать с моим IIS просто отлично). Это приложение () -> дескриптор () сохранить день.
1

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

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

Изменить: просто хедз-ап. Taylor Otwell советует не использовать подзапросы для создания внутренних вызовов API, поскольку они обменивают текущий маршрут. Вы можете использовать HTTP API-клиент, например Guzzle, чтобы вызвать вызовы API.

0

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

    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

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

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню