Categories
Software Development Web Development

Symfony how to get query string values sent by AJAX calls

When using a Symfony API endpoint for getting values such as maybe something like an auto-complete feature you will need to be able to send some text(what the user enters) to the backend. Then have the backend return a response based on that.

For example with an auto complete feature, you might want to send 3 characters to an API endpoint and have it only return a list of words that start with those three characters, instead of returning every last word in the database. This will use less of your servers resources and the users while speeding your app up.

The way I suggest to do this is to first use FosJsRouting bundle in your Javascript to create the URL’s for you. This makes it much easier, faster ( Once you get it installed etc ) and consistent. Here is a long article I wrote about installing and using FosJsRouting bundle How to get URL Routes in your Javascript in Symfony 5+.

This is a short example and doesn’t include checking if the user is logged in ( has rights) if it is an AJAX request, check headers etc. it is just for this example.



/**
     * returns a list of the users image collection names
     * @Route("/get_image_collections", name="get_image_collections", options={"expose"=true},  methods={"GET"})
     */
    public function get_image_collections(Request $request): JsonResponse
    {
        $query = $request->getQueryString();
      $text2 = $request->query->get('text');
      $text =  $request->get("text");
        $values = array(
            'first',
            'second',
            'third',
            'fan',
            'free',
            'narcotics',
            'arse',
            'tardigrade',
            'tinnitus',
            'monkey',
            'mall',
            'doppleganger',
            'ballocks',
            'zoo',
            $query,
            $text,
            $text2
        );
        return new JsonResponse($values);
    }

This is very simple, it doesn’t even hit a database, it is just for this article and testing. All this does right now is return the list and add some text and query so I can see what was sent. In production you might even want to use caching so that your database only gets hit if it has to.

As you can see there appears to be two ways to get the value of the query. Both worked for me, but I am thinking that going through the query method is the proper way like follows.

$request->query->get('text');

The query being used for this endpoint looks like this

"http://sogi-test/get_image_collections?text=fa"

In the future I’ll update the code to include security checks, to return a matching list compiled from a database query and caching.

But notice the (Request $request) that is Dependency Injected ( see symfony dependency injection )

I should also add, below is how I am building the URL with FosJsBundle

let url = Routing.generate('get_image_collections', {text: text});

That is where the “text” named query key is coming from. You can name the key anything you want. If you have more than one named value then use a comma and add it after the first, like in the FosJsRoutingBundle docs under how to use above link.
For example say you want to include something like a page number for paging through results or limiting them etc. You could create the
url route like this

let url = Routing.generate('get_image_collections', {text: text, limit: limit});

This Javascript JSON looks confusing, the first part is the name(key) the second is a(value) variable containing the value
Then to get the values in your controller route you do this.


$text = $request->query->get('text');
$limit = $request->query->get('limit');

You can send as many values as you need to this way. Forms work a little differently. I’ll write an article about those soon too.

And that is how you get the values you send.
baby how it is done meme
That is how it is done

Interesting Error story

I figured I would mention this debugging story I had while sending an ajax request with an improperly formed URL ( aka not matching the route)

I kept getting errors when trying to use Promise.json() with the value returned from my AJAX call. What happened is the server was returning HTML instead of JSON which results in an error when Promise.json() is called.

A while of that and thinking it was my JS code but not really sure of WTF was going on. I finally started outputting my URL to see what was being created and low and behold that was it. I was even watching the Request/Response in the browser. But, it was not obvious until I really started inspecting the created URL vs the route output that I figured out my route and url didn’t match and that was the reason for the redirect.

How to view Symfony routes

 

My route didn’t match because at some point I changed how I wanted the route to look and I had not rerun the FosJsRouting bundle as mentioned in that article to renew the routes in it’s json file.  So it created a URL that didn’t match, the route was created like /route/{text} but the api route expected /route&text=….

I didn’t get an error. Nope and nothing was recorded that I could find in the error logs. Symfony simply redirected ( 301) sent back to my ajax which then somehow did another request to the page I was using the javascript in,  returning the pages HTML.

I was like

Uhm, wait… what?

I have no idea why Symfony redirects when the route doesn’t match.  I don’t even know what setting to adjust where to change this, I know I did something somewhere at sometime… I’ll have to dig into what I did.

Why this happend is because I didn’t re-update the FosJsRouting json file and then restart webpack so it pulls in the new file. But I know there is some sort of setting somewhere for Symfony for the redirect action I am seeing and I know I set it somewhere somehow.

Can I have hamburger now???

By Robert jackson

This is my website. I write articles about programming and more. I've been programming 16 years now.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: