Building a WikiPedia Search Engine App with JS
Tags: javascript, projects, webdev, tutorial
Published: 2020-06-17 17:40:49

I honestly believe that the best way to learn any new technology, programming language, is by building something in that language and putting our knowledge to some practical use.

I receive plenty of messages and queries from some of my dearest friends and juniors asking how to start development, and how to put together the skills they've learnt to actually create something.

While, there are many tutorials on the internet, but most of them are not so beginner friendly, they tend to make a lot of assumptions on the reader's part.

I hope to do my fair duty towards my friends and juniors by writing tutorials on this blog to help grasp several concepts in development and get some apps on their portfolio.

So, without further ado, **Let's Jump right, in!**

## **What We're Gonna Build**

I will take you through how to build a Wikipedia Search App with JavaScript. This project was listed in one of the challenges at [FreeCodeCamp](https://www.freecodecamp.org/challenges/build-a-wikipedia-viewer).

You can actually view a **live version** of the finished project in your browser at,

> #### [wikisearch.ishandeveloper.com](https://wikisearch.ishandeveloper.com)

This is the practical working of the app, from a user-perspective:

1. User can search for Wikipedia articles in a search box and view the results in the app itself.
2. User can visit a random Wikipedia article using the random button.

## Pre-Requisites

Knowledge of basics of HTML, CSS & JavsScript is required as this tutorial is intended for beginners who want to learn how to create simple web apps using JavaScript.  
If you've never built any app before, don't worry! We'll get through this, together!

If you get stuck at any point in this tutorial, you can always refer to the project [source code](https://github.com/ishandeveloper/wikipedia-search-engine) available on GitHub.

## **Let's Get Started**

I have already created a repository with the [starter files](http://wikisearch.ishandeveloper.com/Starter_Files/Starter_Files.zip) for this project, you can download them, [here](http://wikisearch.ishandeveloper.com/Starter_Files/Starter_Files.zip) or from the [Github Repository](https://github.com/ishandeveloper/wikipedia-search-engine).

These starter files contain the basic markups and stylings for this tutorial. We're gonna concentrate only on seeing how the JavaScript works.

Just to ensure that we're all on the same page, before we start

1. Download the Starter Files, from above.
2. Open the project in your preferred code editor (I prefer **VSCode**).
3. Open **index.html** in your browser (or live-server, if you know that sort of thing).
4. In your code editor, open '**_main.js_**' file.

In your browser, you should be able to see, a search bar 🔍 like this :

![Wiki-Search-Bar](https://dev-to-uploads.s3.amazonaws.com/i/5mulxsb26rqiij71s30j.PNG)

Once that's done. Let's proceed to add functionality to our app.
For the sake of easiness, I'm actually splitting this section into three parts, each part targetting a different objective.

**1. Redirecting user to a random article.**
**2. Sending/Recieving search query data from [Wikipedia API](https://www.mediawiki.org/wiki/API:Search) .**
**3. Displaying the search query results on our page.**

Let's start with the first one, as it is the easiest to implement.

### **1. Redirecting user to a random article.**
Remember? One of the functionalities we wanted to add initially was, _'User can visit a random Wikipedia article using the random button'_.

It is fairly easy to do so. In the startup files, I have already created a button, which is actually just an icon enclosed within a link, which I styled to look like a button.

```html
<a href="" class="icon random-ico">
  <i class="fas fa-random"></i>
</a>
```
To achieve this, we can use :

- <mark>`https://en.wikipedia.org/wiki/Special:Random`</mark>

This is a special link, you can try opening it in your browser and you'll be redirected to a random wikipedia article each time. Here's how it can be implemented.

```html
<a
  href="https://en.wikipedia.org/wiki/Special:Random"
  target="_blank"
  rel="noopener noreferrer"
  class="icon random-ico"
>
  <i class="fas fa-random"></i>
</a>
```
Now, you should be able to click on the random button, which takes you to a random wikipedia article.**Voila! Just like that, our first task is complete!**

Here's a **quick breakdown** of the above code,

- <mark>href</mark> attribute refers to the url of the page we're redirecting to.
- <mark>target="\_blank"</mark> helps to ensure that the link always opens in a new tab.
- <mark>rel="noopener noreferrer"</mark> is actually here to help fix a security vulnerability with 'target=\_blank', you can read more on that, <a href="https://www.jitbit.com/alexblog/256-targetblank---the-most-underestimated-vulnerability-ever/">here</a>.

### 2. Sending/Recieving search query data from Wikipedia API .

Okay, so the first task here would be to actually retrieve the data entered into the search bar by the user. Let's do that.

```js
// Grab a reference to form element and store it
const form = document.querySelector(".search-form");
// Add an event listener to form submit event
form.addEventListener("submit", handleSubmit);
```

Here's a breakdown:

- <mark>querySelector()</mark> : It returns the first Element within the document that matches the specified selector, <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector">more on MDN docs</a>.
- <mark>addEventListener</mark> : It takes two arguments: the DOM event we want to listen for and and the function that will run when the event is triggered (in this case, 'submit' is the DOM event & 'handleSubmit' is the function), <a href="sets up a function that will be called whenever the specified event is delivered to the target.">more on MDN docs</a>.

Now, let's move ahead and create `handleSubmit()` function.

```js
function handleSubmit(e) {
  e.preventDefault();
}
```
Here's a breakdown:

- You may have noticed `'e'` as the parameter which is the event that triggered the execution of the function.
- <mark>e.preventDefault()</mark> : By default, the browser has a tendency to refresh the page, whenever a form is submitted. To prevent this, we're using 'preventDefault()' method, <a href="https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault">more on MDN docs</a>.

Our page doesn't reload on form submission, but our function doesn't do anything, right? Let's fix this.

```js
function handleSubmit(e) {
  e.preventDefault();
  let query = document.querySelector(".search-input").value;
  query = query.trim();
  console.log(query);
}
```

You can press **Ctrl+Shift+J / Cmd+Opt+J** to open `console` in chrome and should see an output, once you submit a query in the search bar.

With this, almost half of the job for this step is done! Now, all we have to do is to send the search query to the [Wikipedia API](https://www.mediawiki.org/wiki/API:Search) and fetch the results.

I have already specified the relevant URL parameters, that we'll be using for this tutorial.

```
https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info&origin=*&srlimit=25&utf8=&format=json&srsearch=SEARCH_QUERY
```
#### I'll break this down, quickly:

- <mark>&origin=\*</mark> : It helps us to bypass CORS restrictions, <a href="https://www.mediawiki.org/wiki/API:Cross-site_requests">refer here for more</a>.
- <mark>&srlimit=25</mark> : It helps to specify how many total pages to return (25 in this case), <a href="https://www.mediawiki.org/wiki/API:Search">refer here for more</a>.
- <mark>&format=json</mark> : It helps to specify that we are expecting a JSON response <a href="https://www.mediawiki.org/wiki/API:Search">refer here for more</a>.
- <mark>&srsearch=</mark> : It will contain user's search query <a href="https://www.mediawiki.org/wiki/API:Search">refer here for more</a>.

You can refer to [this page](https://www.mediawiki.org/wiki/API:Search) for more details.

Moving on, we need to make an actual request to Wikipedia and retrieve the results from there. So, let's replace '**`console.log(query);`**' with '**getResults(query);**'.

The handleSubmit function should now look like this :

```js
function handleSubmit(e) {
  e.preventDefault();
  let query = document.querySelector(".search-input").value;
  query = query.trim();
  getResults(query);
}
```

Now, let's create this **`getResults()`** function and fetch the search results. We'll be using template literals to add user's search query parameter into the API URL, mentioned above.

```js
function getResults(query) {
  const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info&origin=*&srlimit=25&utf8=&format=json&srsearch=${query}`;

  fetch(url)
    .then((res) => res.json())
    .then((data) => console.log(data))
    .catch((e) => console.log(`ERROR : ${e}`));
}
```
#### Let's break this down:

- Here we're using back ticks (``` ` ```) for storing the api url in a variable, for more on template literals, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals">refer to MDN docs</a>.
- <mark>fetch()</mark> : This is an inbuilt method, it takes the url as a parameter specifies that we are expecting a JSON response from Wikipedia & returns a <b>Promise</b> Object. <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">more on MDN docs</a>
- The first `.then()` expression returns another Promise so we call a second `.then()` on that to handle the JSON data and log it to the console.
- <mark>.catch()</mark> : is used to catch any errors, that may occur, it'll log an error message to the console if something goes wrong.

Try typing into the input field and submit the form. The raw JSON data will be logged to the console. And with this, we have **successfully completed Step 2**.

### 3. Displaying the search query results on our page.

This is the final step of the tutorial, we have recieved the input, we have got the results, now all we need to do is to display those results.

If you take a closer look at the RAW JSON data, logged to the console in the previous step. You'll see that the data object consists of several keys.

The key named **'search'** is the only one useful to us for now. We can access it using `data.query.search`.

Now that we have the search results, let's first modify the getResults function to display results.

```js
function getResults(query) {
  const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info&origin=*&srlimit=25&utf8=&format=json&srsearch=${query}`;

  fetch(url)
    .then((res) => res.json())
    .then((data) => {
      putResults(data.query.search);
    })
    .catch((e) => console.log(`ERROR : ${e}`));
}
```

Now, let's create a new function'**putResults()**' to which will recieve the search data and add display them on our web page.

```js
function putResults(sResults) {
  // Refer to `.results` section
  const searchResults = document.querySelector(".results");
  searchResults.innerHTML = "";
  // Loop over each result
  sResults.forEach((result) => {
    //Generate a wikipedia page url for each result
    const url = encodeURI(`https://en.wikipedia.org/wiki/${result.title}`);

    //Insert a result item as a child one by one into the parent conainter
    searchResults.insertAdjacentHTML(
      "beforeend",
      `<div class="result">
      <h3 class="result-title">
        <a href="${url}" target="_blank" rel="noopener">${result.title}</a>
      </h3>
      <span class="result-snippet">${result.snippet}</span><br>
      <a href="${url}" class="result-link" target="_blank" rel="noopener">${url}</a>
    </div>`
    );
  });
}
```

And that's it! Is it? **Wait! Don't just leave yet.** Let's see what is actually happening in the code above.

Here's a quick breakdown :

- <mark>encodeURI()</mark> : Please note that <b>URLs Cannot Contain Spaces</b>. Therefore, this method is necessary as it helps to convert unformatted text (with whitespaces), into encoded text.

  - For example: If I pass a search query for 'Linus Torvalds' as a paramter, encodeURI function will return 'Linus%20Torvalds'. For more, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI">refer to MDN docs</a>.

- <mark>sResults.forEach()</mark> : This method is used to iterate over each item of an array, <i>Please Note that instead of using <b>array.forEach</b>, we can also use <b>array.map()</b>. For more, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map">refer to MDN docs</a></i>.

- <mark>insertAdjacentHTML</mark> : It takes two arguments: The position where we want to append the element and a string containing the HTML to insert on the page. For more info, <a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML">refer to MDN docs</a>.

### **Here's The Complete Code**

In case, you need it.

```js
const form = document.querySelector(".search-form");
form.addEventListener("submit", handleSubmit);

function handleSubmit(e) {
  e.preventDefault();
  let query = document.querySelector(".search-input").value;
  query = query.trim();
  getResults(query);
}

function getResults(query) {
  const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info&origin=*&srlimit=25&utf8=&format=json&srsearch=${query}`;

  fetch(url)
    .then((res) => res.json())
    .then((data) => {
      putResults(data.query.search);
    })
    .catch((e) => console.log(`ERROR : ${e}`));
}

function putResults(sResults) {
  const searchResults = document.querySelector(".results");
  searchResults.innerHTML = "";
  sResults.forEach((result) => {
    const url = encodeURI(`https://en.wikipedia.org/wiki/${result.title}`);

    searchResults.insertAdjacentHTML(
      "beforeend",
      `<div class="result">
      <h3 class="result-title">
        <a href="${url}" target="_blank" rel="noopener">${result.title}</a>
      </h3>
      <span class="result-snippet">${result.snippet}</span><br>
      <a href="${url}" class="result-link" target="_blank" rel="noopener">${url}</a>
    </div>`
    );
  });
}
```

With that, we've reached the end of this tutorial. I hope you enjoyed it 😄

This was just to give you a brief look into putting together everything you might've learnt about web development into an actual project.

### If you want to improve this project,

Here are some ideas

- Show a progress indicator while the request is processing.
- Add search suggestions in the search bar, when the user is typing.
- Display results on more than one page.

Originally posted on [my personal blog](https://blog.ishandeveloper.com/wiki-search)

If you'd like to see more quick tutorials such as this, do let me know in the discussions below!