Oh hey there 👋! Have you had the pain of doing search from scratch? Or the feeling of daunt when your PM is like “you know what would be great? If we could have a search bar on website!” and your first thought is...
Yeah, I’ve felt that pain all too many times before. Honestly, I avoided it like the plague a few sprints because even when I did get the search all sorted, I felt like it wasn’t great and on top of that I would be half-way through documentation and wondering wtf, where is that module suppose to go?? really, not super fun.
Nowadays though, we have some great tools and services that makes this much easier for us. RIP building search from scratch days. Gah, I love technology. Making my life easier one day at a time.
This is one of the reasons I started playing with and eventually, joined the team at Algolia. I don’t want this to be one of those articles where you’re reading this like “oh god, she’s pitching me”. No, I genuinely would love to share with you what I learned with getting started at Algolia and how you can get up and coding stat. So let's dive in with some steps you need to get search ready to go.
Obtaining your API keys
Start by creating an account at Algolia. Then grab your credentials from your dashboard. You'll want to copy your App Id
, Search Only API Key
and Admin API Key
.
Once this is complete, add them to whatever you’re using for your .env file
so your app knows how to connect to your Algolia application and index. Boom! That’s the hard part.
Connecting your data source
If you have your data ready to go, we can begin by creating a function to call that url and push it into an index. Let’s use JavaScript as our language here.
const data_url = "https://raw.githubusercontent.com/algolia/datasets/master/movies/actors.json"
function indexData(data_url){
return axios.get(data_url,{})
.then(function(response){
console.log(response.data[0]);
return;
})
.catch(function(error) {
console.warn(error)
})
}
We will build on this function, but for now, it’s just curling that data_url
we pass it, logging the first record we have in the data and returning out of the loop. We are using axios here for our api calls. Axios is a Javascript library used to make http requests from node.js or XMLHttpRequests from the browser and it supports the Promise API that is native to JS ES6. The advantage of using this over others, is that it performs automatic transforms of JSON data.
Prepping Data for Algolia
Now that we are making our call, let’s start using our Algolia account that we set up earlier and upload data to our index! We’ll do this in two steps, first we will iterate over the data we have received back from our axios.get call and make an array of objects. This will let us use only the data we want to highlight in our index. Then, once that is complete we can send to Algolia’s index..
Step 1: Instead of just returning a success response, let’s create a function to handle that upload by passing the response of our axios.get call.
function indexData(data_url){
return axios.get(data_url,{})
.then((response) => {
return dataToAlgoliaObject(response.data)
})
.then(function(response){
return;
})
.catch(function(error) {
console.warn(error)
})
}
Now in this function, we want to go through our data points and create our algolia objects, which should be pretty straight forward loop.
function dataToAlgoliaObject(data_points){
var algoliaObjects = [];
for (var i = 0; i < data_points.length; i++) {
var data_point = data_points[i];
var algoliaObject = {
objectID: data_point.objectID,
name: data_point.name,
rating: data_point.rating,
image_path: data_point.image_path,
alternative_name: data_point.alternative_name
};
algoliaObjects.push(algoliaObject);
}
return algoliaObjects;
}
Step 2: Now that we have built up our objects, they are ready to be sent to Algolia!
Let’s change a few things with our indexData function. We can chain a .then
on our call because of axios promise structure and use async
and await
to make sure nothing gets out of sort before we upload data.
function indexData(data_url){
return axios.get(data_url,{})
.then((response) => {
return dataToAlgoliaObject(response.data)
})
.then(async (response) => {
await sendDataToAlgolia(response);
return;
})
.then(function(response){
return;
})
.catch(function(error) {
console.warn(error)
})
}
Send Data to Algolia
Now, let’s write that sendDataToAlgolia
function. Here is where we will be utilizing the keys we put in our .env
file earlier. We will also need to be sure we have something that initiates our index and passes it the name of the index that we want to use to store our data. Since the dataset we are using is around movie actors, that seems like a good enough name as any to use.
const algoliaClient = algoliasearch(process.env.ALGOLIA_APP_ID, process.env.ALGOLIA_ADMIN_API_KEY);
const algoliaIndex = algoliaClient.initIndex("movie-actors");
function sendDataToAlgolia(algoliaObjects){
return new Promise((resolve, reject) => {
algoliaIndex.addObjects(algoliaObjects, (err, content) => {
if(err) reject(err);
resolve();
})
});
}
Setting your settings
We’ve got data! But, now we want to tell Algolia how we want that data to be used. We can do this via the dashboard or code. I personally like to do via code, so let’s review that here. We have a lot of options, but we can do the basics:
searchableAttributes: list here what you would like searchable from the algoliaObject you created
attributesToHighlight: highlights the text you are searching for
customRanking: choose how your data will be displayed, desc() or asc()
attributesToRetrieve: return these attributes for dislaying in search results
async function configureAlgoliaIndex(){
algoliaIndex.setSettings({
searchableAttributes: [
'name'
],
attributesToHighlight: [
'name'
],
customRanking: [
'desc(rating)'
],
attributesToRetrieve: [
'name',
'rating',
'image_path'
]
});
}
Let’s add this function once we have successfully uploaded data to our index.
function indexData(data_url){
return axios.get(data_url,{})
.then((response) => {
return dataToAlgoliaObject(response.data)
})
.then(async (response) => {
await sendDataToAlgolia(response);
return;
})
.then(async () => {
await configureAlgoliaIndex();
return;
})
.then(function(response){
return;
})
.catch(function(error) {
console.warn(error)
})
}
Wow, now we have data in our index and the way we want it. So, we are done with the back end of things, now onto the part where people can see our sweet sweet data and search for it.
Connecting the front end
Algolia has something called widgets, which allow us to quickly add sections to our HTML page without writing lots of new code. Elements such as a search bar and a place for our Algolia objects to be seen on the page can be easily added in with a few lines of JavaScript. Let’s head over to our client file.
We want to start by creating an instance of instant search we can utilize in our app. You can use cookies to pass this data from the server to the front end or you can have the keys in there. For length sake, we’ll show keys in here.
$(document).ready(function() {
var instantsearch = window.instantsearch;
// create an instantsearch instance with our app id and api key
var search = instantsearch({
appId: Cookies.get('app_id'),
apiKey: Cookies.get('search_api_key'),
indexName: Cookies.get('index_name'),
urlSync: true,
searchParameters: {
hitsPerPage: 3
}
});
Now let’s connect a search input to your html so users have a place to search.
search.addWidget(
instantsearch.widgets.searchBox({
container: '#search-box',
placeholder: 'Search your favorite actors'
})
);
Now we want to adds the results of our data, and in the return statement you can change what you want shown.
search.addWidget(
instantsearch.widgets.hits({
container: '#hits',
hitsPerPage: 12,
templates: {
empty: `<div class="col-md-12" style="text-align: center;"> We didn't find any results for the search <em>\"{{query}}\"</em></div`,
item: function(hit) {
try {
return `
<div class="col-md-4" style="text-align: center;">
<p>
<h3 class="hit-text">${hit._highlightResult.name.value}</h3>
<img src="https://image.tmdb.org/t/p/w45/${hit.image_path}" height="50" width="50">
</p>
<p>
Rating: ⭐️ ${hit.rating}
</p>
</div>
`;
} catch (e) {
console.warn("Couldn't render hit", hit, e);
return "";
}
}
}
})
);
A good search experience shouldn't overwhelm the user with results, so, let’s add pagination to the results we're getting back.
search.addWidget(
instantsearch.widgets.pagination({
container: '#pagination'
})
);
Last but not least… let’s start the search! This instantiates everything on your page.
search.start();
Of course, if you want to skip all this manual work, you can check out our quickstart app on Glitch, remix it and you’ll have all this code with a basic working app out of the box with about 5 minutes of effort.😉 Happy reading and hope this helped!
Top comments (6)
We're happy users of Algolia for a few key features on dev.to and plan to expand our use. 🙂
Algolia is really fantastic. I use DocSearch for documentation at UI-licious, and it's blissfully easy to install, and the search results are really great - beautiful search box with just the right amount of detail to help you figure out where is the information you need.
Awesome to hear, Shi! I love DocSearch, it's great to get up and running straight away and I dig that helps make our community information easier to find. 🙌
So... you are effectively outsourcing your site search to an external service? Please tell me I'm wrong, please... I can't even begin to describe how wrong this feels to me.
1) You actually pay for on-site-search, something integral to your page
2) If the other service is down, your site may be up, but your search doesn't work. Your customers are going to love that.
3) If there is ever technical trouble with the service you are using, you can't fix it. You completely depend on it.
4) You are subject to somebody else's data structures, just for searching
5) Searching is honestly not that hard to do, even in a homebrew solution, or just use a server with a proper DB, or even elasticsearch or Lucene/SOLR if you want.
Sorry folks, I would consider it if it were a library, but depending on an external service for something trivial as a search bar (no matter how good it is) is an absolute no-go in my book.
There's nothing trivial about the infrastructure behind the product. We have a globally distributed Algolia implementation for low-latency across the world.
Like our various CDNs and other cloud services, yes, we depend on them. A lot of software is built with cloud services these days.
I am planning to use it for my current project but I prefer to find an open-source alternative if exists