How to Integrate Typesense Search Engine in a Nodejs application
Tags: webdev, javascript, tutorial, node
Published: 2021-12-01 22:48:37

Tried building an application that requires efficient search? Maybe an online store or library catalog system?

 It is hard to build search engines that are typo tolerant, effective and efficient. A typographical error could make a search return nothing even though the requested item is on the database.
Typesense could save you and your app users from such stress as you would not need to spend time building a search engine. And your users can effectively use the search feature in your application which would give them a great user experience.
Typesense is an open-source typo-tolerant search engine for developers, developed to reduce the time to market for apps that require effective and efficient search.

## **In this article, we will cover the following:**

- Setting up Typesense Cloud
- Setting up our nodejs app
- Initializing the client
- Creating a Typesense Collection
- Setting up the express app
- Adding item to our collection
- Searching our collection

## **Setting up Typesense Cloud**

You can use Typesense by either installing its docker image on your server or using the Typesense cloud hosting solution, which is the easiest way to get started with it, so we are using this option. Click [Here](https://cloud.typesense.org/) to get started and sign in with Github.

Once authenticated, follow these steps.

1. Scroll down and launch a cluster wait for about 4 to 6 minutes.
    

![Creating A Cluster](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7e7qrxptw09g87h6fo7h.png)
    
2. Click on Generate API Keys. It will download a text file containing credentials needed to authenticate our app with Typesense cloud.

![Generate API Key ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u033tj1o7n1dvpm24j4d.png)

## Setting Up the Nodejs App

Follow these steps, if you have Nodejs installed on your system if you don't download the latest version [here](https://nodejs.org/) and follow the steps.

```
npm init
```

Install the following packages `express`,  `typesense` and `nodemon` by running the following command

```
npm i express typesense nodemon
```

Add `"dev": "nodemon app.js"` to the script part of the package.json file.

```json
"scripts": {
		"start": "node app.js",
    "dev": "nodemon app.js"
  },
```

After these are done, setup the project structure to look like this.

📦express-typesense-app

┣ 📂Typesense

┃ ┣ 📜bookCollection.js

┃ ┗ 📜client.js

┣ 📜app.js

┣ 📜package.json

┗ 📜package-lock.json

## **Initializing the client**

Navigate to the `Typesense` Folder, paste codes below in the `client.js` file, The first line imports `Typesense` into our code, then we create a `Typesense Client` instance, this instance receives an object of configurations, needed to authenticate our app with Typesense, next we export this `client` so it will be available for other files. Fill in the information gotten from the text file downloaded when you generated API keys, since we are running on the backend and we want to have write access use the Admin API Key.

```js
const Typesense = require('typesense')

const client = new Typesense.Client({
  nodes: [{
    host: 'your-typesense-node-gotten-from-type-sense-cloud', // For Typesense Cloud use xxx.a1.typesense.net
    port: '443',      // For Typesense Cloud use 443
    protocol: 'https'   // For Typesense Cloud use https
  }],
  apiKey: 'your-typesense-admin-api-key-gotten-from-type-sense-cloud',
  connectionTimeoutSeconds: 5
})

module.exports = client
```

## Creating a Typesense Collection

Typesense, a collection is a group of related documents, by are like tables in relational a database. When we create a collection, we give it a name and describe the fields that will be indexed when a document is added to the collection.

For each field, we define its `name, type`, and whether it's a `facet` field. A facet field allows us to cluster the search results into categories. 

We also define a `default_sorting_field` that determines how the results must be sorted when no `sort_by` clause is provided. In this case, books that have more ratings will be ranked higher.  This line of code `client.collections().create(booksSchema)` create the book collection from the book schema. 

> This code will throw an error if the collection already exists, to prevent the app from this crashing handle the Error, by calling the error callback. as done in the code below `err => {}`.
> 

```js

const booksSchema = {
    'name': 'books',
    'fields': [
      {'name': 'title', 'type': 'string' },
      {'name': 'authors', 'type': 'string[]', 'facet': true },
      {'name': 'image_url', 'type': 'string' },
      {'name': 'publication_year', 'type': 'int32', 'facet': true },
      {'name': 'ratings_count', 'type': 'int32' },
      {'name': 'average_rating', 'type': 'float' }
    ],
    'default_sorting_field': 'ratings_count'
  }
  
client.collections().create(booksSchema)
  .then( data => {

  }, err => {
 
  });
```

## Setting up the express server

Create `app.js` on the root directory of the application, we import the `express` this is needed to create an express server, line 2 imports the Typesense `client` this client will be used to make requests to Typesense, line 3 creates the book Collection if it doesn't exist.

```js
const express = require('express');
const client= require('./Typesense/client');
require('./Typesense/bookCollection')
```

Here we create an express app, the next two lines of codes attach the middleware needed for the app to receive post data from post request.

```js
const app = express();

app.use(express.urlencoded({ extended: true }));
app.use(express.json());
```

### Searching for books in our collection

This route handles GET requests to `localhost:3000/search?q=`, the first line of code in this route get the user search input from the `q` query, the second line builds the search object `searchParameters`, from the search object we see that we are querying our books by its `title` and sorting by `ratings_count` in descending order, `res.send(searchResults)` sends the search results to the client.

```js

app.get('/search', (req, res) => {

  const { q } = req.query;

  const searchParameters = {
    'q'         : q,
    'query_by'  : 'title',
    'sort_by'   : 'ratings_count:desc'
  }
  
  client.collections('books')
    .documents()
    .search(searchParameters)
    .then(function (searchResults) {
      res.send(searchResults)
    }, err => { res.send(error) } )
});
```

### Adding data to book collection

This route handles POST request to `localhost:3000/add-book`,  the first line of code get the body of the post request, which in this case is the book we want to add to our collection `client.collections('books').documents().create(book)` add the book to our collection. `res.send(data)` sends the book data to the client.

```js

app.post('/add-book', (req, res) => {

  const book = req.body;
  
  client.collections('books').documents().create(book).then(data => {
    res.send(data)
  }, err => {
    res.send(err)
  })
 
});
```

This codeblock runs the server on port `3000`

```js

const port = process.env.PORT || 3000;

const server = app.listen(port, () => {
  console.log(`App running on port ${port}...`);
});
```

## Adding Item to our Collection

I will be using Postman to test this app, if you are new to Postman, click [here](https://www.postman.com/) to download it, set up a workspace, and create a collection.

I added 3 books to the book collection,  titled `How to use Typesense in a Nodejs application`, `I want to Dance`, `Best Dance Move` with the following ratings respectively 4.55, 3.55, 4.35.

![Adding Books](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wmnhbl2ksgzjsbb2052i.png)

## Searching for Item in our Collection

Searching for a book titled ***Best Dance Moves***, Noticed, I deliberately made errors in the spelling by searching ***Bezt Dense Movee***

and Typesense returns Two books that contain the word Dance in its title.

![Searching For Book](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z0uuvmzfjbp64b1r7edn.png)

Searching for a "Harry Potter" which is not in our book collection returns zero items.

![Harry Potter search](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yg6o9fljd577dwebon9m.png)

## Conclusion

In this article, we talk about Typesense and how to get started with Typesense cloud, connecting to Typesense cloud, we created a typesense collection. We used the Typesense javascript library, this library works also works on Web Browsers, when used on Web Browser, use the search API key that doesn't grant write access. Typesense supports other languages click [here](https://typesense.org/docs/guide/building-a-search-application.html#sample-dataset) to learn about them.

Using Postman to test our application we saw that Typesense is very typo tolerant, easy to use, and fast.