How can I access query string parameters for requests I've manually dispatched in Laravel 4?

39,429

Solution 1

You are correct in that using Input is actually referencing the current request and not your newly created request. Your input will be available on the request instance itself that you instantiate with Request::create().

If you were using (as you should be) Illuminate\Http\Request to instantiate your request then you can use $request->input('key') or $request->query('key') to get parameters from the query string.

Now, the problem here is that you might not have your Illuminate\Http\Request instance available to you in the route. A solution here (so that you can continue using the Input facade) is to physically replace the input on the current request, then switch it back.

// Store the original input of the request and then replace the input with your request instances input.
$originalInput = Request::input();

Request::replace($request->input());

// Dispatch your request instance with the router.
$response = Route::dispatch($request);

// Replace the input again with the original request input.
Request::replace($originalInput);

This should work (in theory) and you should still be able to use your original request input before and after your internal API request is made.

Solution 2

I was also just facing this issue and thanks to Jason's great answers I was able to make it work.

Just wanted to add that I found out that the Route also needs to be replaced. Otherwise Route::currentRouteName() will return the dispatched route later in the script.

More details to this can be found on my blog post.

I also did some tests for the stacking issue and called internal API methods repeatedly from within each other with this approach. It worked out just fine! All requests and routes have been set correctly.

Share:
39,429
Kevin Mitchell
Author by

Kevin Mitchell

Updated on April 22, 2020

Comments

  • Kevin Mitchell
    Kevin Mitchell about 4 years

    I'm writing a simple API, and building a simple web application on top of this API.

    Because I want to "consume my own API" directly, I first Googled and found this answer on StackOverflow which answers my initial question perfectly: Consuming my own Laravel API

    Now, this works great, I'm able to access my API by doing something like:

    $request = Request::create('/api/cars/'.$id, 'GET');
    $instance = json_decode(Route::dispatch($request)->getContent());
    

    This is great! But, my API also allows you to add an optional fields parameter to the GET query string to specify specific attributes that should be returned, such as this:

    http://cars.com/api/cars/1?fields=id,color
    

    Now the way I actually handle this in the API is something along the lines of this:

    public function show(Car $car)
    {
         if(Input::has('fields'))
         {
              //Here I do some logic and basically return only fields requested
              ....
         ...
     }
    

    I would assume that I could do something similar as I did with the query string parameter-less approach before, something like this:

    $request = Request::create('/api/cars/' . $id . '?fields=id,color', 'GET');
    $instance = json_decode(Route::dispatch($request)->getContent());
    

    BUT, it doesn't seem so. Long story short, after stepping through the code it seems that the Request object is correctly created (and it correctly pulls out the fields parameter and assigns id,color to it), and the Route seems to be dispatched OK, but within my API controller itself I do not know how to access the field parameter. Using Input::get('fields') (which is what I use for "normal" requests) returns nothing, and I'm fairly certain that's because the static Input is referencing or scoping to the initial request the came in, NOT the new request I dispatched "manually" from within the app itself.

    So, my question is really how should I be doing this? Am I doing something wrong? Ideally I'd like to avoid doing anything ugly or special in my API controller, I'd like to be able to use Input::get for the internally dispatched requests and not have to make a second check , etc.

  • Jason Lewis
    Jason Lewis almost 11 years
    One thing to keep in mind here is the possibility of an internal request calling another internal request. You might need to keep a stack of requests and store the original input as well, then pop the the last request off the stack and replace the input accordingly.
  • Kevin Mitchell
    Kevin Mitchell almost 11 years
    THanks for the info! Yeah, I ended up creating a very simple model that does nothing but basically handles swapping out these bits of data automatically before, after I "execute" the request. Thanks again for the info!
  • whonoes
    whonoes almost 10 years
    Any way to attach headers to the created request (for sending a public api key with the request for example)?
  • Sukhpreet Singh Alang
    Sukhpreet Singh Alang over 9 years
    This url returns a 404
  • neoteknic
    neoteknic almost 8 years
    Request::replace doesn't exist
  • Tho
    Tho almost 8 years