Api

Search API Reference

Last updated by
Harlan Wilton
in chore: sync.

Endpoint

POST /api/search

Semantic search endpoint with optional query rewriting.

Request

Request Body

interface SearchRequest {
  query: string        // Required: Search query
  limit?: number       // Optional: Max results (default: 10)
  query_id?: string    // Optional: Query identifier
}

Example

curl -X POST "https://example.com/api/search" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "nuxt modules",
    "limit": 10
  }'

Response

Success Response (200)

interface SearchResponse {
  query_id?: string
  results: SearchResult[]
}

interface SearchResult {
  url: string
  name: string
  score: number
  description?: string
  markdown?: string
}

Example:

{
  "query_id": "abc123",
  "results": [
    {
      "url": "/guide/module-development",
      "name": "Module Development Guide",
      "score": 0.89,
      "description": "Learn how to build Nuxt modules",
      "markdown": "# Module Development\n\nModule development involves..."
    }
  ]
}

Field Descriptions

Response Fields

  • query_id: Optional query identifier (returned if provided in request)
  • results: Array of search results

Result Fields

  • url: Page URL/route
  • name: Page title
  • score: Relevance score (0-1, higher is better)
  • description: Page description/summary (optional)
  • markdown: Relevant markdown content (optional)

Error Responses

400 Bad Request

Missing Query:

{
  "statusCode": 400,
  "message": "Query parameter is required"
}

Invalid Limit:

{
  "statusCode": 400,
  "message": "Limit must be between 1 and 100"
}

500 Internal Server Error

Index Not Found:

{
  "statusCode": 500,
  "message": "Vector database not found. Make sure the site has been built."
}

Hook System

ai-search:search:query

Transform query before search execution (e.g., query rewriting).

export default defineNitroPlugin((nitro) => {
  nitro.hooks.hook('ai-search:search:query', async (ctx, result) => {
    // Modify query before search
    result.query = ctx.query + ' synonyms here'
  })
})

Context:

interface SearchQueryContext {
  query: string
  event: H3Event
  limit: number
  model?: LanguageModel
  config: RuntimeConfig
}

ai-search:search:results

Post-process search results (e.g., filtering, reranking).

export default defineNitroPlugin((nitro) => {
  nitro.hooks.hook('ai-search:search:results', async (ctx, result) => {
    // Filter results by score
    result.results = result.results.filter(r => r.score > 0.5)
  })
})

Context:

interface SearchResultsContext {
  query: string
  results: SearchResult[]
  event: H3Event
  config: RuntimeConfig
}

Query Rewriting

The module includes built-in query rewriting via the ai-search:search:query hook.

Configuration:

nuxt.config.ts
export default defineNuxtConfig({
  aiSearch: {
    llm: {
      provider: 'openai',
      model: 'gpt-4o-mini',
      apiKey: process.env.OPENAI_API_KEY
    },
    queryRewriting: {
      enabled: true,
      systemPrompt: 'Expand the query with relevant synonyms...'
    }
  }
})

Note: Query rewriting is automatically disabled for models <7B params.

Examples

curl -X POST "https://example.com/api/search" \
  -H "Content-Type: application/json" \
  -d '{"query": "installation"}'

Limit Results

curl -X POST "https://example.com/api/search" \
  -H "Content-Type: application/json" \
  -d '{"query": "nuxt modules", "limit": 5}'

With Query ID

curl -X POST "https://example.com/api/search" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "how to create plugins",
    "limit": 10,
    "query_id": "user-123-query-1"
  }'

JavaScript/TypeScript

// Fetch API
const response = await fetch('/api/search', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    query: 'nuxt modules',
    limit: 10
  })
})
const data = await response.json()

// Nuxt composable
const results = await $fetch('/api/search', {
  method: 'POST',
  body: {
    query: 'nuxt modules',
    limit: 10
  }
})

Performance

Typical Response Times

  • Query embedding generation: <100ms
  • Vector similarity search: <50ms
  • Total response time: <200ms typical

Optimization

  • Vector DB indexes embeddings for fast cosine search
  • Query rewriting adds ~100-500ms (LLM call)
  • Results cached on vector DB layer

CORS

To allow cross-origin requests:

nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/api/search': {
      cors: true,
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'POST, OPTIONS',
        'Access-Control-Allow-Headers': 'Content-Type'
      }
    }
  }
})

TypeScript Types

import type {
  SearchRequest,
  SearchResponse,
  SearchResult
} from 'nuxt-ai-search'

const request: SearchRequest = {
  query: 'nuxt modules',
  limit: 10
}

const response: SearchResponse = await $fetch('/api/search', {
  method: 'POST',
  body: request
})

Next Steps

Did this page help you?