Search API for restaurants [Tutorial]

Demo dashboard for movies API is here (angular.js)
Example has 10000 fake restaurants with geolocation, rating and likes
Note: This tutorial is from May 2016. Some things may be not up-to-date. Sorry for that.

Introduction

In this tutorial I will show you how to create search backend for big list of restaurants with ItemsAPI (based on elasticsearch & node.js). 

This is ideal for mobile (android, iOS, ionic) and frontend (angular, react.js) developers. This is also for backend developers who would like to make things easier than before.

Why ?

Using it you:

  • save weeks or months on programming 
  • get very fast and flexible search backend
  • get generated REST endpoints for searching and managing items (json) 
  • get simple recommendation - users who likes this item (restaurant) also like
  • have sorting items by geolocation
  • have access to the dashboard for managing and visualizing your items

The whole process of creating such a API is simple and take only few minutes on heroku with one-click-deploy and a little bit more on localhost if you don’t have installed elasticsearch yet.

Installation and running

Heroku

There are two ways of creating search backend for restaurants. The first one is one-click-deploy with heroku. This is painless and the easiest way to start. You don’t need to install anything here.  Deploy

Manual installation

The second method is manual installation on your localhost. You need to install node.js, npm and elasticsearch and run these commands:

$ git clone [email protected]:itemsapi/itemsapi-starter.git
$ cd itemsapi-starter
$ npm install
$ PORT=3000 npm start

Open http://localhost:3000 or heroku url in your browser and you will get backend web creator with two short steps. The first one is adding collection configuration and second one is adding items (json objects)

1. Add collection

Copy & paste below collection configuration into first step textarea form. It is responsible for data schema, sortings and filters (aggregations) options. It looks quite long but it is responsible for the whole API logic

{
  "name": "restaurants",
  "type": "restaurants",
  "index": "restaurants",
  "defaults": {
    "sort": "rating"
  },
  "schema": {
    "name": {
      "type": "string",
      "store": true
    },
    "city": {
      "type": "string",
      "store": true,
      "index": "not_analyzed"
    },
    "country": {
      "type": "string",
      "index": "not_analyzed",
      "store": true
    },
    "country_icon": {
      "type": "string",
      "display": "image"
    },
    "rating": {
      "type": "float"
    },
    "likes": {
      "type": "string",
      "index": "not_analyzed",
      "store": true
    },
    "geo": {
      "type": "geo_point"
    }
  },
  "sortings": {
    "rating": {
      "title": "Rating",
      "type": "normal",
      "order": "desc",
      "field": "rating"
    },
    "country": {
      "title": "Country",
      "type": "normal",
      "order": "asc",
      "field": "country"
    },
    "distance": {
      "title": "Distance",
      "type": "geo",
      "order": "asc",
      "field": "geo"
    },
    "city": {
      "title": "City",
      "type": "normal",
      "order": "asc",
      "field": "city"
    }
  },
  "table": {
    "fields": [
      "country_icon",
      "name",
      "country",
      "city",
      "rating",
      "geo"
    ]
  },
  "aggregations": {
    "country": {
      "type": "terms",
      "field": "country",
      "size": 10,
      "title": "Country"
    },
    "distance_ranges": {
      "type": "geo_distance",
      "field": "geo",
      "ranges": [
        {
          "lte": 500,
          "name": " 1000"
        }
      ],
      "unit": "km",
      "title": "Distance ranges [km]"
    },
    "ratings": {
      "type": "range",
      "field": "rating",
      "title": "Rating",
      "ranges": [
        {
          "lte": 2,
          "name": "1 - 2"
        },
        {
          "lte": 3,
          "gte": 2,
          "name": "2 - 3"
        },
        {
          "gte": 3,
          "lte": 4,
          "name": "3 - 4"
        },
        {
          "gte": 4,
          "name": "4 - 5"
        }
      ]
    }
  }
}

name - this is collection id. index and type are the elasticsearch internal names (not required)
schema - types of fields and how do we store and search them
sortings - the ways of sorting table - useful only for angular dashboard for generating html table out of the box aggregations - very powerful feature for generating filters

More information and explanation about all options are in documentation

2. Adding data

The backend is already working. The last thing which you need to do is add the data. Here is the link https://raw.githubusercontent.com/itemsapi/itemsapi-example-data/master/items/restaurants.json with 1000 restaurants with geolocation, fake names, likes (for recommendation) and ratings. 

Just copy and paste the url to the input in second step and submit. Your backend is just generated and you will see the list of most important endpoints here.

That’s all! Your backend is ready and you can now focus on building mobile app, single page application or just a standard website.

Finish! (Rest endpoints)

List of few generated endpoints:

GET /api/v1/items/restaurants (list of restaurants)
GET /api/v1/items/restaurants?sort=distance&around_lat_lng=52.5120804,13.4526408 (list of restaurants and sorted by distance)
GET /api/v1/items/restaurants
GET /api/v1/items/restaurants/:id/similar?fields=likes (similar items to item :id based on collaborative filtering)

More info about endpoints here: (https://itemsapi.readme.io/docs/rest-endpoints)

Usages

It was an example for restaurants but ItemsAPI is very flexible and you can be very creative with how you can use it. The list of possibilities is probably unlimited but there is list of few examples:

  • hotels, cars, bicycles, some products, cities, foods, people, places
  • movies, books, quotes

Everything what you need to make backend is providing proper configuration and data. 

More info

For more information about ItemsAPI:

Summary

Thank you for spending your time for reading that tutorial. Will be happy to hear any feedback from you!