DEV Community

Cover image for Adding Dynamic Search Auto-Complete to a web application with NodeJS and React 🔍
Kuvam Bhardwaj
Kuvam Bhardwaj

Posted on

Adding Dynamic Search Auto-Complete to a web application with NodeJS and React 🔍

Introduction

You must've seen google's autocomplete search bar predict your next keystrokes as you type in it

google autocomplete search feature

So, I thought of building one and sharing my findings with y'all.
Let's get started 🚀

Google's search auto-complete API

I was making an app that required me to implement this sort of thing where a user starts typing and some search suggestions would come flying in his face (in a div of course). So I started to wander around on google for some free APIs. In the quest, I stumbled upon this stack overflow discussion. One of the answers suggested to use:

https://www.google.com/complete/search?client=hp&hl=en&sugexp=msedr&gs_rn=62&gs_ri=hp&cp=1&gs_id=9c&q=a&xhr=t&callback=hello
Enter fullscreen mode Exit fullscreen mode

This basically is the URL that google.com itself uses for its search suggestions

google.com search suggestions page with inspector opened at network tab

API Endpoint

Let's now get on writing some GET requests to google's API from a test browser environment, I find codesandbox.io the best way to set up a quick hosted web environment for such things.

code sandbox code to fetch google auto-complete search API

And.....refresh!

access control origin error from browser environment

Hmm, so this is a CORS error, relatively easy to fix only if you know how to work with NodeJS ;)

"What just happened?"

These errors happen when a header Access-Control-Allow-Origin is not present. Responses from requests that don't have this header are blocked by the browser even if the request returns 200 OK.

The Access-Control-Allow-Origin response header indicates whether the response can be shared with requesting code from the given origin.

Find more on this header here. This error is only raised in a browser environment. Therefore, now we will be switching this request-making code block to a node environment and then return the response to the requesting client for our node API endpoint.

Also, if we just make a GET request with our local machine, like on postman or insomnia. It will be returning a normal response for our specified url-encoded query q

200 OK insomnia response for google auto-complete search api

Now, let's code our node endpoint to get the search suggestions and return them as a JSON response.

replit nodejs app to fetch and return autocomplete search results as json

For quick code snippets instantly deployed in a hosted environment, I often like to use replit.com.
In this code, I imported express (for spinning up a web server) and axios (for making GET/POST requests to sources over the internet).

Then, I initialized the express server/app and defined an API GET ENDPOINT with the .get(url, (request, response) => {}) method, made a GET request with axios to google's API and sent the returned suggestions data to the requesting client.

Testing the newly made endpoint, will obviously return a 200 OK response and provide us with the search results

I am the best in nodejs

But there is 1 more task remaining with our endpoint, returning nice & sweetly formatted search suggestions in the JSON format

code to format returned data

For this part of the code, I referenced the main part of the result with some indexing, used regular expressions to grab just the part where it gives the actual completion text, and add some null checks for the regex matches. Now our API response looks something like this

nice and sweet response

Implementing the API in a React application

So, now comes the part where we actually use our API to dynamically suggest users for their search keystrokes. On code sandbox, let's spin up a basic react app that takes input & saves it in its state

basic react app with simple input state

Now, we don't want to spam our endpoint with dozens of requests on every keystroke whenever the input value is changed. So, we'll be implementing a timeout-based request fetching, something like this

import axios from "axios";
import { useState } from "react";

export default function App() {
  const [searchResults, setSearchResults] = useState([]);
  const [inputText, setInputText] = useState("");
  const [inputTimer, setInputTimer] = useState(null);

  const handleInputChange = async (e) => {
    setInputText(e.target.value);

    clearTimeout(inputTimer);
    let timeout = setTimeout(() => {
      console.log("FETCHING RESULTS");
      axios
        .get(
          `https://autocomplete-google-search.kuvambhardwaj.repl.co/autocomplete?q=${e.target.value}`
        )
        .then((res) => {
          setSearchResults(res.data);
        });
    }, 300);
    setInputTimer(timeout);
  };

  return (
    <div className="App">
      <center>
        <input
          value={inputText}
          onChange={handleInputChange}
          placeholder="Type something"
          style={{ fontSize: "24px" }}
        />

        <div style={{ marginTop: "30px" }}>
          <ul>
            {searchResults.map((searchResult) => (
              <li>{searchResult}</li>
            ))}
          </ul>
        </div>
      </center>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

So, now what we're doing is set a timeout for like 300ms whenever the input value changes & store the timeout reference in the state, if the user enters a letter and the input value is changed within 300ms, it will clear the previously set timeout and initialize a new one. After 300ms of input inactivity, we will be finally making autocomplete request with the most recent value of the input.
The application should work something like this

working thingy


If you like my posts, consider following :)

Twitter -> @BhardwajKuvam

Github -> @kuvamdazeus

LinkedIn -> @kuvambhardwaj

Portfolio -> kuvambhardwaj.vercel.app

Top comments (0)