Gandalf
Gandalf

Reputation: 13683

Using next js 13 with elastic search

I have this api route

import { Client } from "@elastic/elasticsearch";
import { NextResponse } from "next/server";

export async function GET(request) {
  try {
    const client = new Client({ node: "http://localhost:9200" });

    const { body } = await client.search({
      index: "game-of-thrones",
      size: 100,
      body: {
        query: {
          match_all: {}
        }
      }
    });

    const hits = body.hits?.hits || [];
    const documents = hits.map((hit) => hit._source);

    return NextResponse.json(documents, { status: 200 });
  } catch (error) {
    console.error("Elasticsearch Error:", error);
    return NextResponse.error();
  }
}

and this client side page

'use client';
import { useEffect, useState } from 'react';

export default function Home() {
  const [documents, setDocuments] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch('/api/all');
        const data = await response.json();
        setDocuments(data);
        setLoading(false);
      } catch (error) {
        console.error('Error fetching documents:', error);
      }
    };

    fetchData();
  }, []);

  return (
    <main>
      {loading ? (
        <p>Loading...</p>
      ) : (
        <div>
          {documents.map((document) => (
            <div key={document._id}>
              <h2>{document.character}</h2>
              <p>{document.quote}</p>
            </div>
          ))}
        </div>
      )}
    </main>
  );
}

I am trying to read from an existing index but i keep getting this error

Elasticsearch Error: TypeError: Cannot read properties of undefined (reading 'hits')
    at GET (webpack-internal:///(sc_server)/./src/app/api/all/route.js:24:27)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:244:37)
- error RangeError [ERR_HTTP_INVALID_STATUS_CODE]: Invalid status code: 0
    at new NodeError (node:internal/errors:399:5)
    at ServerResponse.writeHead (node:_http_server:344:11)
    at ServerResponse.writeHead (c:\admin\node_modules\next\dist\compiled\compression\index.js:46:263)
    at ServerResponse._implicitHeader (node:_http_server:335:8)
    at ServerResponse.end (c:\admin\node_modules\next\dist\compiled\compression\index.js:22:749)
    at sendResponse (c:\admin\node_modules\next\dist\server\send-response.js:49:30)
    at doRender (c:\admin\node_modules\next\dist\server\base-server.js:970:62)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async cacheEntry.responseCache.get.incrementalCache.incrementalCache (c:\admin\node_modules\next\dist\server\base-server.js:1162:28)
    at async c:\admin\node_modules\next\dist\server\response-cache\index.js:99:36 {
  code: 'ERR_HTTP_INVALID_STATUS_CODE'
}

My index looks like this

{"took":3,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":25,"relation":"eq"},"max_score":1.0,"hits":[{"_index":"game-of-thrones","_id":"XHsmMIgBAA3lxqgqah3Y","_score":1.0,"_source":{"character":"Ned Stark","quote":"Winter is coming."}},{"_index":"game-of-thrones","_id":"W3smMIgBAA3lxqgqaR0g","_score":1.0,"_source":{"character":"Ned Stark","quote":"Winter is coming."}},{"_index":"game-of-thrones","_id":"XXsmMIgBAA3lxqgqbB1T","_score":1.0,"_source":{"character":"Daenerys Targaryen","quote":"I am the blood of the dragon."}},{"_index":"game-of-thrones","_id":"XnsmMIgBAA3lxqgqbB3p","_score":1.0,"_source":{"character":"Tyrion Lannister","quote":"A mind needs books like a sword needs a whetstone."}},{"_index":"game-of-thrones","_id":"X3smMIgBAA3lxqgq7h3K","_score":1.0,"_source":{"character":"Ned Stark","quote":"Winter is coming."}},{"_index":"game-of-thrones","_id":"YHsmMIgBAA3lxqgq7x0h","_score":1.0,"_source":{"character":"Daenerys Targaryen","quote":"I am the blood of the dragon."}},{"_index":"game-of-thrones","_id":"YXsmMIgBAA3lxqgq7x2O","_score":1.0,"_source":{"character":"Tyrion Lannister","quote":"A mind needs books like a sword needs a whetstone."}},{"_index":"game-of-thrones","_id":"YnsmMIgBAA3lxqgq8R3R","_score":1.0,"_source":{"character":"Ned Stark","quote":"Winter is coming."}},{"_index":"game-of-thrones","_id":"Y3smMIgBAA3lxqgq8h0i","_score":1.0,"_source":{"character":"Daenerys Targaryen","quote":"I am the blood of the dragon."}},{"_index":"game-of-thrones","_id":"ZHsmMIgBAA3lxqgq8h12","_score":1.0,"_source":{"character":"Tyrion Lannister","quote":"A mind needs books like a sword needs a whetstone."}}]}}

How can i return the documents that i want?

Upvotes: 1

Views: 1481

Answers (1)

Gandalf
Gandalf

Reputation: 13683

I have managed to fix it this way

Server

import { Client } from "@elastic/elasticsearch";
import { NextResponse } from "next/server";

export async function GET(request) {
  try {
    const client = new Client({ node: "http://localhost:9200" });

    const { body } = await client.search({
      index: "game-of-thrones",
      query: {
        match_all: {}
      }
    }, { meta: true });

    console.log('body', body);

    return NextResponse.json(body, { status: 200 });
  } catch (error) {
    console.error("Elasticsearch Error:", error);
    return NextResponse.error();
  }
}

Client

'use client';
import { useEffect, useState } from 'react';

export default function Home() {
  const [documents, setDocuments] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch('/api/all');
        const data = await response.json();
        setDocuments(data.hits.hits.map((hit) => hit._source));
        setLoading(false);
      } catch (error) {
        console.error('Error fetching documents:', error);
      }
    };

    fetchData();
  }, []);

  return (
    <main>
      {loading ? (
        <p>Loading...</p>
      ) : (
        <div>
          {documents.map((document, index) => (
            <div key={index}>
              <h2>{document.character}</h2>
              <p>{document.quote}</p>
            </div>
          ))}
        </div>
      )}
    </main>
  );
}

Upvotes: 1

Related Questions