FEAT: Video Search In Discovery
Build, Push and Deploy Discovery / build-push-deploy (push) Successful in 1m57s
Build, Push and Deploy Discovery / build-push-deploy (push) Successful in 1m57s
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
@@ -47,3 +48,76 @@ func GetVideo(w http.ResponseWriter, r *http.Request) {
|
||||
Categories: append([]string{}, video.Categories...),
|
||||
})
|
||||
}
|
||||
|
||||
const (
|
||||
// searchPageSize is how many videos a search returns when the caller does
|
||||
// not say. Small enough to keep the common request cheap.
|
||||
searchPageSize = 20
|
||||
|
||||
// maxSearchPageSize is the largest page the catalogue will build, however
|
||||
// big a page the caller asks for. The endpoint is read constantly, and a
|
||||
// page size is a request for work: without a ceiling, one client asking
|
||||
// for the whole catalogue in a single response makes every other reader
|
||||
// wait behind it.
|
||||
//
|
||||
// Asking for more is not an error — the page is simply capped, and the
|
||||
// cursor still reaches the rest — because a client that wants everything
|
||||
// is doing something legitimate, just not in one request.
|
||||
maxSearchPageSize = 100
|
||||
)
|
||||
|
||||
// SearchVideos serves the catalogue's lexical search.
|
||||
//
|
||||
// It is served on QUERY rather than GET or POST: a search is safe and
|
||||
// idempotent, which POST is not, but its parameters are a structured document
|
||||
// that does not belong in a query string. QUERY says both. It is specified in
|
||||
// draft-ietf-httpbis-safe-method-w-body, not in RFC 9110 — still a draft, so
|
||||
// expect intermediaries that have never heard of it. Note it also cannot be
|
||||
// expressed in the generated OpenAPI spec — Swagger 2.0 and OpenAPI 3.x define a fixed set of
|
||||
// per-method fields with no slot for QUERY, and swag rejects the annotation
|
||||
// outright — so this endpoint is deliberately absent from /swagger and
|
||||
// documented here instead.
|
||||
func SearchVideos(w http.ResponseWriter, r *http.Request) {
|
||||
var request api.SearchRequest
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
|
||||
writeProblem(w, http.StatusBadRequest, "Malformed Search",
|
||||
"The request body could not be read as JSON. Send a JSON object describing what to search for; an empty object browses the whole catalogue.")
|
||||
return
|
||||
}
|
||||
|
||||
limit := request.Limit
|
||||
if limit <= 0 {
|
||||
limit = searchPageSize
|
||||
}
|
||||
if limit > maxSearchPageSize {
|
||||
limit = maxSearchPageSize
|
||||
}
|
||||
|
||||
found, next, err := repositories.VideoRepo.SearchVideos(r.Context(), request.Title, request.Categories, limit, request.Cursor)
|
||||
if errors.Is(err, repositories.ErrInvalidCursor) {
|
||||
writeProblem(w, http.StatusBadRequest, "Malformed Search Cursor",
|
||||
"The cursor could not be read. Send back the nextCursor from a previous search unchanged, or omit it to start from the first page.")
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("Something Went Wrong Searching The Catalogue: title=%q: %s", request.Title, err)
|
||||
writeProblem(w, http.StatusInternalServerError, "Something Went Wrong Searching The Catalogue",
|
||||
"The catalogue could not be searched. This is a server-side fault and the request was not processed; retrying in a few moments may succeed.")
|
||||
return
|
||||
}
|
||||
|
||||
// Translated field by field, for the same reason GetVideo does it: the row
|
||||
// and the published schema are different things.
|
||||
videos := make([]api.Video, 0, len(found))
|
||||
for _, v := range found {
|
||||
videos = append(videos, api.Video{
|
||||
ID: v.ID,
|
||||
Title: v.Title,
|
||||
PlaybackURL: v.PlaybackURL,
|
||||
Categories: append([]string{}, v.Categories...),
|
||||
})
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, api.SearchResults{Videos: videos, NextCursor: next})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user