5 - Add Search Results
The final step is implementing Search Results, which provide users with a detailed list of results based on their query. This feature is essential for delivering comprehensive answers and guiding users to relevant resources.
Search Requests
You will use the /search
endpoint to perform searches using the Raffle API. This endpoint requires three key parameters:
uid
, which identifies the search instance or tool;session-id
, a unique identifier for the user session to group related searchesquery
, which represents the search term provided by the user.
Additionally, the endpoint supports optional parameters like preview
and device
.
preview
set to true ensures the request is excluded from the training data and the analytic insights, making it ideal for testing your implementation.device
allows you to specify the user’s device type, such as “desktop” or “mobile,” to provide device-tuned search experiences and ensure the Insights dashboard shows proper information about your users’ sessions.
Note: When implementing this endpoint, it is important to manage session IDs properly to maintain accurate data grouping and insights. During testing, always use the preview parameter to prevent test data from affecting live results. Accurately setting the device parameter can enhance the search experience by accounting for device-specific behavior.
Search Response
Search results returned by the /search
endpoint include a feedback_data
property. This property is designed to be used when users interact with a result. Therefore, you need to send the feedback_data
to the Raffle API using the /feedback
endpoint, to help Raffle improve search relevance and accuracy over time. Additionally, this feedback property provides valuable insights by tracking which results users find most useful, allowing for continuous optimization and better decision-making.
Note: The search implementation will work without you sending the feedback_data
property to the /feedback
. However, it is essential to the accurate functionality of the “Search Inquiries”. If feedback_data
is not used, then the “Click-Through Rate” will remain 0 as not all the required information is available for calculations.
You can find more information about the /feedback
endpoint in our API Reference
API Call
Here’s the function to fetch search results from the Raffle API. This function sends a GET
request to the search
endpoint using the user’s query and returns a list of search results.
export const fetchSearchResults = async (query) => {
const response = await fetch(
`https://api.raffle.ai/v2/search?uid=$YOUR_RAFFLE_UID&query=${query}&session-id=${sessionId}&preview=${preview}&device=${device}`
);
const data = await response.json();
return data.results;
};
Here is the POST
request to the feedback
endpoint
export const sendFeedback = async (feedback_data) => {
const response = await fetch('https://api.raffle.ai/v2/feedback', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ type: 'click', feedback_data }),
})
const data = response.json();
return data;
}
Integration of Search API Calls
We’ll use React Query’s useMutation
to fetch the search results dynamically when a search is triggered.
import { useState } from "react";
import { useMutation } from "@tanstack/react-query";
import { fetchSearchResults, sendFeedback } from "./api/api";
export const Search = () => {
const [query, setQuery] = useState("");
// Mutation for fetching search results
const {
data: results = [],
isPending: isLoadingResults,
mutate: handleFetchResults,
} = useMutation({
mutationKey: ["search"],
mutationFn: fetchSearchResults,
});
// Mutation for sending feedback
const { mutate: handleSendFeedback } = useMutation({
mutationKey: ["feedback"],
mutationFn: sendFeedback,
});
// Function to handle search submission
const handleSearch = () => {
if (query.trim()) {
handleFetchResults(query.trim());
}
};
return (
<div>
<h1>Search API - React Example</h1>
<div>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Enter your query..."
/>
<button onClick={handleSearch}>Search</button>
</div>
<div>
<h2>Search Results</h2>
{isLoadingResults ? (
<p>Loading...</p>
) : results.length > 0 ? (
<ul>
{results.map((result) => (
<li key={result.url}>
<a href={result.url} target="_blank" rel="noopener noreferrer" onClick={() => handleSendFeedback(result.feedback_data)}>
<h3>{result.title}</h3>
</a>
<p>{result.content}</p>
</li>
))}
</ul>
) : (
<p>No results available for this query.</p>
)}
</div>
</div>
);
};
Explanation
fetchSearchResults
: Fetches detailed search results for a given query from the API.useMutation
: Dynamically fetches search results when a search is triggered.- Loading State: Displays a loading indicator while the results are being fetched.
- Rendering Results: Displays a list of results with titles, descriptions, and clickable links.
This step completes the search flow by adding the core functionality of displaying comprehensive search results.
Final Code Implementation
At this stage, your full code should look like this:
import { useEffect, useState } from "react";
import { useMutation, useQuery } from "@tanstack/react-query";
import { useDebounce } from "@uidotdev/usehooks";
import {
fetchSearchResults,
sendFeedback,
fetchSuggestions,
fetchSummary,
fetchTopQuestions,
} from "./api";
export const Search = () => {
const [query, setQuery] = useState("");
const debouncedQuery = useDebounce(query, 500); // Debounce with 500ms delay
// Fetch top questions
const { data: topQuestions = [], isLoading } = useQuery({
queryKey: ["topQuestions"],
queryFn: fetchTopQuestions,
});
// Mutation for fetching suggestions
const { data: suggestions = [], mutate: handleFetchSuggestions } =
useMutation({
mutationKey: ["suggestions", debouncedQuery],
mutationFn: fetchSuggestions,
});
// Mutation for fetching summary
const {
data: summary,
isPending: isLoadingSummary,
mutate: handleFetchSummary,
} = useMutation({
mutationKey: ["summary"],
mutationFn: fetchSummary,
});
// Mutation for fetching search results
const {
data: results = [],
isPending: isLoadingResults,
mutate: handleFetchResults,
} = useMutation({
mutationKey: ["search"],
mutationFn: fetchSearchResults,
});
// Mutation for sending feedback
const { mutate: handleSendFeedback } = useMutation({
mutationKey: ["feedback"],
mutationFn: sendFeedback,
});
// Trigger suggestions when debouncedQuery is at least 3 characters long
useEffect(() => {
if (debouncedQuery.length >= 3) {
handleFetchSuggestions(debouncedQuery);
}
}, [debouncedQuery, handleFetchSuggestions]);
// Handle search action
const handleSearch = () => {
if (query.trim()) {
handleFetchSummary(query.trim());
handleFetchResults(query.trim());
}
};
return (
<div>
<h1>Search API - React Example</h1>
{/* Search Input */}
<div>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Enter your query..."
/>
<button onClick={handleSearch}>Search</button>
</div>
{/* Top Questions Section */}
<div>
<h2>Top Questions</h2>
{isLoading ? (
<p>Loading top questions...</p>
) : (
<ul>
{topQuestions.map(({ question }) => (
<li key={question} onClick={() => setQuery(question)}>
{question}
</li>
))}
</ul>
)}
</div>
{/* Suggestions Section */}
<div>
<h2>Suggestions</h2>
<ul>
{suggestions.map(({ suggestion }, index) => (
<li
key={index}
onClick={() => {
setQuery(suggestion);
handleSearch();
}}
>
{suggestion}
</li>
))}
</ul>
</div>
{/* Summary Section */}
<div>
<h2>Summary</h2>
{isLoadingSummary ? (
<p>Loading...</p>
) : summary ? (
<div>
<div dangerouslySetInnerHTML={{ __html: summary.summary }} />
{summary.references.length > 0 && (
<div>
<h3>References</h3>
<ul>
{summary.references.map((ref) => (
<li key={ref.url}>
<a
href={ref.url}
target="_blank"
rel="noopener noreferrer"
>
{ref.title}
</a>
</li>
))}
</ul>
</div>
)}
</div>
) : (
<p>No summary available for this query.</p>
)}
</div>
{/* Search Results Section */}
<div>
<h2>Search Results</h2>
{isLoadingResults ? (
<p>Loading...</p>
) : results.length > 0 ? (
<ul>
{results.map((result) => (
<li key={result.url}>
<a href={result.url} target="_blank" rel="noopener noreferrer" onClick={() => handleSendFeedback(result.feedback_data)}>
<h3>{result.title}</h3>
</a>
<p>{result.content}</p>
</li>
))}
</ul>
) : (
<p>No results available for this query.</p>
)}
</div>
</div>
);
};