import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
import { products, Product } from "../shared/data.js";
interface SearchRequest {
query: string;
maxResults?: number;
category?: string;
}
interface SearchResult {
product: Product;
relevance: number;
}
/**
* POST /api/products/search - Search products by query string
* Request body:
* - query: Search query (required)
* - maxResults: Maximum number of results (default: 10)
* - category: Optional category filter
*/
export async function searchProducts(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
context.log(`searchProducts function processed a request`);
let body: SearchRequest;
try {
body = await request.json() as SearchRequest;
} catch {
return {
status: 400,
jsonBody: {
success: false,
error: "Invalid JSON body"
}
};
}
const { query, maxResults = 10, category } = body;
if (!query || typeof query !== "string") {
return {
status: 400,
jsonBody: {
success: false,
error: "Query parameter is required"
}
};
}
const queryLower = query.toLowerCase();
// Simple relevance scoring based on matches in name and description
let results: SearchResult[] = products
.map(product => {
let relevance = 0;
// Check name match (higher weight)
if (product.name.toLowerCase().includes(queryLower)) {
relevance += 0.6;
}
// Check description match
if (product.description.toLowerCase().includes(queryLower)) {
relevance += 0.3;
}
// Check category match
if (product.category.toLowerCase().includes(queryLower)) {
relevance += 0.1;
}
return { product, relevance };
})
.filter(r => r.relevance > 0);
// Apply category filter if specified
if (category) {
results = results.filter(r =>
r.product.category.toLowerCase() === category.toLowerCase()
);
}
// Sort by relevance and limit results
results = results
.sort((a, b) => b.relevance - a.relevance)
.slice(0, maxResults);
return {
status: 200,
jsonBody: {
success: true,
query,
count: results.length,
results: results.map(r => ({
...r.product,
relevance: Math.round(r.relevance * 100) / 100
}))
}
};
}
app.http("searchProducts", {
methods: ["POST"],
authLevel: "function",
route: "products/search",
handler: searchProducts
});