---
title: "GET /api/search"
method: GET
path: "/api/search"
tags: ["Search"]
---

# GET /api/search

`GET /api/search`

## Request

- The document declares no server URL.
- Auth: none declared

Search the public catalogue (courses, lessons and blog posts) by what they
say, in the request locale. The text is a web search query: words are
matched by their stems in the language of the locale, a phrase in quotes
is kept together, `or` and a leading `-` work as people expect, and nothing
typed is an error. The best matches come first. Only what a visitor can read
on the website is found: no draft, unpublished post or unlisted page.

## Query parameters

- `q` string, required
- `type` 'course' | 'lesson' | 'post': The kinds of record the catalogue search finds.
- `page` integer
- `perPage` integer

## Response `200`

The request has succeeded.

- SearchResultPage: A page of results. Generic envelope reused by every admin list so the CRUD engine (TanStack Table) can read pagination uniformly.
  - `items` SearchResult[], required
    - `type` 'course' | 'lesson' | 'post', required: The kinds of record the catalogue search finds.
    - `id` string, required: A typed, stable id made of what the page's URL carries. A course is `course:LANDING_SLUG`, the slug `getCourse` takes. A lesson is `lesson:COURSE_SLUG/LESSON_SLUG`, the two slugs `getCourseLesson` takes. A post is `post:SLUG`, the slug `getBlogPost` takes.
    - `title` string, required
    - `snippet` string, required: A few words of the record's text around the match, plain text; empty when only the title matched and the record has no text.
    - `path` string, required: The record's page on the website: the locale prefix and the path, with no origin.
  - `total` integer, required: Total rows across all pages (before pagination).
  - `page` integer, required: 1-based page number this response represents.
  - `perPage` integer, required: Page size used for this response.

## Other responses

- `default`: Default error response shared by every operation. `@error` emits an OpenAPI `default` response, keeping central transport failures typed without enumerating every status on every operation.

## Changes

- **2026-10-18** `9380d4c85a04`: 1 info
  - added the optional property `errors` to the response with the `default` status
- **2026-10-18** `23cc12c79080`: 1 info
  - endpoint added
- **2026-10-17** `738ba9d74100`: 1 breaking
  - api path removed without deprecation
- **2026-10-17** `2a151bc91508`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/hexlet-basics/apis/hexlet-basics-api/changes/api/search/get.md)

---

[API](https://skmtc.dev/hexlet-basics/apis/hexlet-basics-api.md) · [All operations](https://skmtc.dev/hexlet-basics/apis/hexlet-basics-api/llms.txt) · [OpenAPI document](https://skmtc.dev/hexlet-basics/apis/hexlet-basics-api/revisions/51c7f596b47c?raw)
