DEV Community

Cover image for How to Use Elasticsearch APIs ?
Wanda
Wanda

Posted on • Originally published at apidog.com

How to Use Elasticsearch APIs ?

TL;DR

Elasticsearch APIs enable scalable search and analytics. Index documents as JSON, query using the DSL, and aggregate results for analytics. Authenticate using API keys or basic auth. Use Apidog to validate index mappings, test search queries, and debug aggregations before deploying to production clusters.

Try Apidog today

Introduction

Elasticsearch is a distributed search and analytics engine for structured text, logs, metrics, and more. It’s commonly used for full-text search in applications, log analysis, and real-time analytics dashboards.

Elasticsearch is part of the ELK stack (Elasticsearch, Logstash, Kibana), but you can use its APIs directly—no Logstash required.

💡 Tip: If you’re building search features or log analysis, Apidog helps you test queries, validate mappings, and debug aggregations. Save and share search templates with your team.

Test Elasticsearch APIs with Apidog — free

By the end of this guide, you’ll be able to:

  • Index and manage documents
  • Write search queries with Elasticsearch DSL
  • Use aggregations for analytics
  • Configure mappings and analyzers
  • Monitor cluster health

Getting started

Run Elasticsearch locally

# Docker
docker run -p 9200:9200 \
  -e "discovery.type=single-node" \
  elasticsearch:8.11.0

# Or download from elastic.co
Enter fullscreen mode Exit fullscreen mode

Verify installation

curl -X GET "http://localhost:9200"
Enter fullscreen mode Exit fullscreen mode

Expected response:

{
  "name": "elasticsearch-1",
  "cluster_name": "elasticsearch",
  "cluster_uuid": "abc123",
  "version": {
    "number": "8.11.0",
    "build_flavor": "default"
  },
  "tagline": "You know, for search"
}
Enter fullscreen mode Exit fullscreen mode

Authentication

Elasticsearch 8.x requires authentication by default:

curl -X GET "http://localhost:9200/_cluster/health" \
  -u elastic:your_password
Enter fullscreen mode Exit fullscreen mode

Or use API keys (generate via Kibana or API).


Indices and documents

Create an index

curl -X PUT "http://localhost:9200/products" \
  -u elastic:your_password \
  -H "Content-Type: application/json" \
  -d '{
    "settings": {
      "number_of_shards": 1,
      "number_of_replicas": 0
    },
    "mappings": {
      "properties": {
        "name": { "type": "text" },
        "price": { "type": "float" },
        "category": { "type": "keyword" },
        "in_stock": { "type": "boolean" },
        "created_at": { "type": "date" }
      }
    }
  }'
Enter fullscreen mode Exit fullscreen mode

Index a document

curl -X POST "http://localhost:9200/products/_doc" \
  -u elastic:your_password \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Wireless Headphones",
    "price": 79.99,
    "category": "electronics",
    "in_stock": true,
    "created_at": "2026-03-24T10:00:00Z"
  }'
Enter fullscreen mode Exit fullscreen mode

Response:

{
  "_index": "products",
  "_id": "abc123",
  "_version": 1,
  "result": "created",
  "_seq_no": 0,
  "_primary_term": 1
}
Enter fullscreen mode Exit fullscreen mode

Get a document

curl -X GET "http://localhost:9200/products/_doc/abc123" \
  -u elastic:your_password
Enter fullscreen mode Exit fullscreen mode

Update a document

curl -X PUT "http://localhost:9200/products/_doc/abc123" \
  -u elastic:your_password \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Wireless Headphones Pro",
    "price": 99.99,
    "category": "electronics",
    "in_stock": true,
    "created_at": "2026-03-24T10:00:00Z"
  }'
Enter fullscreen mode Exit fullscreen mode

Delete a document

curl -X DELETE "http://localhost:9200/products/_doc/abc123" \
  -u elastic:your_password
Enter fullscreen mode Exit fullscreen mode

Bulk operations

Efficiently index multiple documents:

curl -X POST "http://localhost:9200/products/_bulk" \
  -u elastic:your_password \
  -H "Content-Type: application/x-ndjson" \
  -d '{"index":{"_id":"1"}}
{"name":"Product A","price":10.99,"category":"books","in_stock":true}
{"index":{"_id":"2"}}
{"name":"Product B","price":20.99,"category":"electronics","in_stock":false}
'
Enter fullscreen mode Exit fullscreen mode

Search queries

Basic search

curl -X GET "http://localhost:9200/products/_search" \
  -u elastic:your_password \
  -H "Content-Type: application/json" \
  -d '{
    "query": {
      "match": {
        "name": "headphones"
      }
    }
  }'
Enter fullscreen mode Exit fullscreen mode

Bool queries

Combine multiple conditions:

{
  "query": {
    "bool": {
      "must": [
        { "match": { "name": "headphones" } }
      ],
      "filter": [
        { "term": { "category": "electronics" } },
        { "range": { "price": { "lte": 100 } } },
        { "term": { "in_stock": true } }
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Full-text search with scoring

{
  "query": {
    "multi_match": {
      "query": "wireless audio headphones",
      "fields": ["name^2", "description"],
      "type": "best_fields",
      "fuzziness": "AUTO"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Fields with ^2 have double weight in scoring.

Phrase search

Find exact phrases:

{
  "query": {
    "match_phrase": {
      "description": "noise canceling"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Wildcard and regex

{
  "query": {
    "wildcard": {
      "name": "*headphone*"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Sorting

{
  "query": { "match_all": {} },
  "sort": [
    { "price": "asc" },
    { "_score": "desc" }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Pagination

{
  "from": 20,
  "size": 10,
  "query": { "match_all": {} }
}
Enter fullscreen mode Exit fullscreen mode

Aggregations

Aggregations compute summary statistics on your data.

Average price by category

curl -X GET "http://localhost:9200/products/_search" \
  -u elastic:your_password \
  -H "Content-Type: application/json" \
  -d '{
    "size": 0,
    "aggs": {
      "by_category": {
        "terms": { "field": "category" },
        "aggs": {
          "avg_price": { "avg": { "field": "price" } },
          "min_price": { "min": { "field": "price" } },
          "max_price": { "max": { "field": "price" } }
        }
      }
    }
  }'
Enter fullscreen mode Exit fullscreen mode

Histogram of prices

{
  "size": 0,
  "aggs": {
    "price_histogram": {
      "histogram": {
        "field": "price",
        "interval": 25
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Date histograms

{
  "size": 0,
  "aggs": {
    "sales_over_time": {
      "date_histogram": {
        "field": "created_at",
        "calendar_interval": "month"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Cardinality (unique counts)

{
  "size": 0,
  "aggs": {
    "unique_categories": {
      "cardinality": { "field": "category" }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Mappings and analyzers

Field types

Type Use for
text Full-text search, analyzed
keyword Exact values, filtering, sorting
integer, float Numbers
boolean True/false
date Dates and times
object Nested JSON objects
nested Arrays of objects (maintains relationships)
geo_point Lat/lon coordinates

Custom analyzers

For specialized text processing:

{
  "settings": {
    "analysis": {
      "analyzer": {
        "autocomplete": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["lowercase", "autocomplete_filter"]
        }
      },
      "filter": {
        "autocomplete_filter": {
          "type": "edge_ngram",
          "min_gram": 2,
          "max_gram": 20
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "autocomplete",
        "search_analyzer": "standard"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Cluster management

Cluster health

curl -X GET "http://localhost:9200/_cluster/health"
Enter fullscreen mode Exit fullscreen mode

Example response:

{
  "cluster_name": "elasticsearch",
  "status": "green",
  "number_of_nodes": 3,
  "active_primary_shards": 25
}
Enter fullscreen mode Exit fullscreen mode

Statuses:

  • green: All shards allocated
  • yellow: Replicas not allocated (single node)
  • red: Primary shards missing

Index statistics

curl -X GET "http://localhost:9200/_cat/indices?v"
Enter fullscreen mode Exit fullscreen mode

Node statistics

curl -X GET "http://localhost:9200/_nodes/stats"
Enter fullscreen mode Exit fullscreen mode

Clear cache

curl -X POST "http://localhost:9200/_cache/clear"
Enter fullscreen mode Exit fullscreen mode

Testing with Apidog

Elasticsearch queries can be complex. Always test thoroughly.

1. Save common queries

Store search templates in Apidog:

{
  "query": {
    "bool": {
      "must": [
        { "match": { "{{search_field}}": "{{search_term}}" } }
      ],
      "filter": [
        { "range": { "{{price_field}}": { "lte": "{{max_price}}" } } }
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

2. Validate responses

pm.test('Search returns results', () => {
  const response = pm.response.json()
  pm.expect(response.hits.total.value).to.be.above(0)
})

pm.test('Aggregations present', () => {
  const response = pm.response.json()
  pm.expect(response.aggregations).to.exist
})
Enter fullscreen mode Exit fullscreen mode

3. Environment separation

# Local
ES_HOST: http://localhost:9200
ES_USER: elastic
ES_PASSWORD: your_password

# Production
ES_HOST: https://search.yourcompany.com
ES_API_KEY: prod_api_key
Enter fullscreen mode Exit fullscreen mode

Test Elasticsearch APIs with Apidog — free


Common errors and fixes

403 Forbidden

Cause: Authentication failed or insufficient permissions.

Fix: Verify credentials. Check API key permissions.

404 index_not_found_exception

Cause: Index does not exist.

Fix: Create the index first. Avoid auto-creation for production.

circuit_breaking_exception

Cause: Query uses too much memory.

Fix: Reduce size, simplify queries, or add filters.

search_phase_execution_exception

Cause: Query syntax error.

Fix: Check your JSON syntax and field paths.


Alternatives and comparisons

Feature Elasticsearch OpenSearch Meilisearch Typesense
Setup Self-hosted Self-hosted Single binary Single binary
Search quality Excellent Good Excellent Good
Learning curve Steep Steep Easy Easy
Scalability Excellent Excellent Good Good
Cloud offering Elastic Cloud OpenSearch Serverless Meilisearch Cloud Typesense Cloud

Elasticsearch offers the most features and largest community. Meilisearch and Typesense are easier for basic search use cases.


Real-world use cases

  • E-commerce search: Retail sites index large product catalogs. Users search by name, description, category, and price. Autocomplete and filters enhance UX.
  • Application logs: DevOps teams ship logs to Elasticsearch (e.g., via Filebeat). Engineers search logs by service, severity, and time range. Dashboards visualize errors and performance.
  • Security analytics: Security teams index network logs, search for suspicious IPs, visualize patterns, and set up anomaly alerts using aggregations.

Wrapping up

Key takeaways:

  • Index documents as JSON
  • Query using Elasticsearch DSL
  • Leverage aggregations for analytics
  • Configure mappings for optimal search
  • Monitor cluster health

Next steps:

  1. Run Elasticsearch locally
  2. Create an index with mappings
  3. Index test documents
  4. Write search queries
  5. Try aggregations

Test Elasticsearch APIs with Apidog — free


FAQ

What’s the difference between Elasticsearch and Solr?

Both are Lucene-based search engines. Elasticsearch features better distributed design and APIs. Solr has more enterprise features, but most new projects use Elasticsearch.

How do I handle special characters in search?

Escape special characters: ()[]{}:^"\+-!~*?| with a backslash. Or use simple_query_string for more forgiving syntax.

What’s a shard?

Shards are parts of an index. Each shard is a Lucene index. Primary shards handle writes; replica shards are copies for reads and fault tolerance.

How many shards should I create?

Rule of thumb: 20-50GB per shard. Start with 1 primary shard and add replicas. Only increase primary shards when necessary (cannot decrease).

Can I change mappings after indexing?

Partially—add new fields anytime. To change existing field types, reindex data. Use index templates for consistent mappings.

What’s the _routing parameter?

Routes documents to specific shards based on a field value. Default is _id. Use routing if queries always filter by a specific field (e.g., user_id) for better performance.

How do I handle time-based data?

Use date-based indices: logs-2026.03.24. This approach allows old data to be deleted by dropping indices and improves query performance by targeting fewer indices.

Top comments (0)