Thuta Learning
AdvancedData & Databasesbeginner

Using the Node.js/TypeScript Client

What you'll walk away with

  • Explain the core ideas behind Using the Node.js/TypeScript Client
  • Run the sample Elasticsearch query or code and verify its output
  • Apply the technique correctly to the Tutorial Platform and production scenarios

Build the mental model

Every lesson so far taught Kibana Dev Tools's shorthand HTTP syntax, but production application code manually building raw `fetch`/`curl` calls with string concatenation is error-prone — URL encoding, JSON serialization, connection pooling, and retry logic all need to be handled by hand. The official `@elastic/elasticsearch` Node.js client abstracts all of that away, and its TypeScript type definitions let you type-check a Query DSL object at compile time — a typo you'd only notice at runtime inside a raw JSON string shows up instantly in your editor instead. Connecting through the client library gives you built-in connection pooling, so you no longer create a new TCP connection per request — share one client instance as a singleton across a Node.js server process. The client's method calls map directly onto Query DSL structures as JavaScript/TypeScript objects, so porting a query from Kibana Dev Tools is straightforward (`GET /tutorials/_search` plus a JSON body becomes `client.search({ index: 'tutorials', query: {...} })`) — this is the payoff of what Lesson 7 promised: Dev Tools syntax ports simply into a client method call.

Connect it to a real scenario

Inside the Tutorial Platform's Next.js API route (`/api/search`), export a module-level singleton client instead of creating a new `Client` instance per request, so every route handler imports and reuses it, sharing a single connection pool per process. Write the Dev Tools `match` plus `bool` query as a TypeScript object literal and `await client.search<TutorialDoc>({ index: 'tutorials', query: {...} })` — passing the generic type parameter `TutorialDoc` lets field-name typos in `hits.hits[].source` get caught at compile time. Pass the Elasticsearch URL and API key from environment variables into the client config, so local dev and production switch through a single configuration.

Try the working example

typescript
import { Client } from '@elastic/elasticsearch';

export const esClient = new Client({
  node: process.env.ELASTICSEARCH_URL,
  auth: { apiKey: process.env.ELASTICSEARCH_API_KEY! },
});

interface TutorialDoc {
  title: string;
  body: string;
  difficulty: string;
}

export async function searchTutorials(term: string) {
  const result = await esClient.search<TutorialDoc>({
    index: 'tutorials',
    query: { match: { body: term } },
  });
  return result.hits.hits.map((hit) => hit._source);
}
You should see
You write a type-safe search function that returns an array of tutorial documents with TypeScript types.

5-minute try-it

Using the `Client` singleton, write a `searchByDifficulty(term, difficulty)` function that runs a `bool` query (`match` plus `filter`) filtered on `difficulty` — make the return type `TutorialDoc[]`.

One important caution

Instantiating `new Client(...)` again on every API route call or function invocation — losing the shared connection pool and opening excessive TCP connections wastefully.

Leaving `client.search()`'s result untyped as `any` instead of passing the `TutorialDoc` type parameter — a field-name typo (`hits.hits[].source.titl`) is no longer caught at compile time at all.

elasticsearch-js — GitHubElastic

Easy traps

  • Instantiating `new Client(...)` again on every API route call or function invocation — losing the shared connection pool and opening excessive TCP connections wastefully.
  • Leaving `client.search()`'s result untyped as `any` instead of passing the `TutorialDoc` type parameter — a field-name typo (`hits.hits[].source.titl`) is no longer caught at compile time at all.
  • Validate sample queries and requests on a local or test instance with recoverable data before applying them to production.

Exercise

Using the `Client` singleton, write a `searchByDifficulty(term, difficulty)` function that runs a `bool` query (`match` plus `filter`) filtered on `difficulty` — make the return type `TutorialDoc[]`.

You'll know it worked when: You write a type-safe search function that returns an array of tutorial documents with TypeScript types.

Using the Node.js/TypeScript Client | Thuta Learning