Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

12 — API Mapping (Search Module)

Exact wire contract for global search. Envelope shapes are authoritative from 00-shared/07_API_Conventions.md (success/error envelopes, pagination meta, error codes, rate limits). Endpoint facts from search.controller.ts, search.service.ts, search-query.dto.ts.


1. Endpoint inventory

MethodPathPermissionSource
GET/api/v1/searchsearchsearch.controller.ts:11,15-16; permissions.constants.ts:93
  • Base URL https://api.<domain>/api/v1 (00-shared/07 §1).
  • Auth: Authorization: Bearer <accessToken>JwtAuthGuard (search.controller.ts:3,10); Swagger @ApiBearerAuth() (:9).
  • This is the only endpoint in the module. Plan-only: (planned) coaching-index extension needs no new endpoint (same GET /searchdocs/IMPLEMENTATION_PLAN.md:771).

2. Query parameters (exact)

ParamTypeDefaultConstraintSource
qstringoptional, no length capsearch-query.dto.ts:6-9
entityTypestringoptional, free-form (client sends known types)search-query.dto.ts:11-14
pageint1≥ 1search-query.dto.ts:16-21
limitint201..50search-query.dto.ts:23-29

Out-of-range page/limit, non-integer values → 400 VALIDATION_ERROR (00-shared/07 §3).

3. Success response (exact shape)

{
  "success": true,
  "message": "OK",
  "data": [
    {
      "entityType": "Student",
      "entityId": "66f1c0a5e8b2c1d4f5a6b7c8",
      "title": "Rahul Sharma",
      "description": "rahul@school.edu",
      "tags": ["grade5"]
    }
  ],
  "meta": { "page": 1, "limit": 20, "totalItems": 1, "totalPages": 1,
            "hasNext": false, "hasPrevious": false },
  "timestamp": "2026-08-03T09:00:00.000Z",
  "requestId": "req-…"
}
  • data = array of SearchResult (search.service.ts:10-16,51-57).
  • meta = buildPaginationMeta(page, limit, totalItems) (pagination-query.dto.ts:41-55); note totalPages never drops below 1 (:46).
  • totalItems = full-text count (search.service.ts:37); when entityType filtering trims a page, totalItems is replaced by the filtered page length (search.service.ts:44-49) — see QA-14 §7.
  • Relevance score (textScore) is used for sort only and never serialized (search-index.repository.ts:28-33; search.service.ts:51-57).

4. Empty query response

q blank/whitespace → data: [], meta.totalItems: 0, totalPages: 1 (search.service.ts:28-30). 200, not an error.

5. Error responses (client-relevant)

HTTPCodeWhenSource
400VALIDATION_ERRORinvalid page/limit/typessearch-query.dto.ts; 00-shared/07 §3
401UNAUTHENTICATEDmissing/expired tokenJwtAuthGuard (search.controller.ts:10)
403PERMISSION_DENIEDno search permission@Permissions('search') (search.controller.ts:16; permissions.constants.ts:93)
429RATE_LIMITEDper-tier limits (00-shared/07 §4)global rate limit guards
5xxINTERNAL_SERVER_ERRORinternal (incl. regex-fallback failure)00-shared/07 §3

Server-side resilience: $text failure is caught and retried via regex fallback before any error reaches the client (search.service.ts:35-41).

6. Request example (curl)

GET /api/v1/search?q=rahul%20sharma&entityType=Student&page=1&limit=20
Authorization: Bearer <accessToken>

7. Client mapping (widget → endpoint)

Screen (05)RequestKey handling
Search barGET /search?q=… (debounced 300 ms)drop stale responses (13 §3)
Results screensame + infinite scroll (page++)append; meta.hasNext gate (pagination-query.dto.ts:52)
See-all&entityType=Xreplace list, page 1
Refreshsame query, page 1replace list

8. Non-goals

  • No POST /search, no bulk, no suggestions, no history endpoints — anything beyond GET /search is (forward-looking) / (planned).
  • Search results are not cached in Redis todayRedisCacheService (redis-cache.service.ts:16-19) is available but unwired (proposed).