aboutsummaryrefslogtreecommitdiff
path: root/internal/api/api.go
diff options
context:
space:
mode:
authorEthan Lee <ethanalee@google.com>2026-03-11 20:57:08 +0000
committerGopher Robot <gobot@golang.org>2026-03-24 13:03:38 -0700
commit86d1c7b3f2f2d36dbaf488d847c09e1655356ca7 (patch)
tree6f6acbe695a2a5dcdc971685a5b4d3faa6426efe /internal/api/api.go
parent2a28a75de8607004c628480a40a1ecfc9d3cdfe1 (diff)
downloadgo-x-pkgsite-86d1c7b3f2f2d36dbaf488d847c09e1655356ca7.tar.xz
internal/api: implement search endpoint
- Implement ServeSearch method and pagination for search results. Change-Id: I109d0861b5fa0cfbc20ce20308561ef6b5616405 Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/754860 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> kokoro-CI: kokoro <noreply+kokoro@google.com> Auto-Submit: Ethan Lee <ethanalee@google.com> Reviewed-by: Jonathan Amsterdam <jba@google.com>
Diffstat (limited to 'internal/api/api.go')
-rw-r--r--internal/api/api.go61
1 files changed, 57 insertions, 4 deletions
diff --git a/internal/api/api.go b/internal/api/api.go
index 1d21ba7e..d1419c40 100644
--- a/internal/api/api.go
+++ b/internal/api/api.go
@@ -19,6 +19,13 @@ import (
"golang.org/x/pkgsite/internal/version"
)
+const (
+ // maxSearchResults is the maximum number of search results to return for a search query.
+ maxSearchResults = 1000
+ // searchResultsPerPage is the number of search results to return per page for paginated search results.
+ searchResultsPerPage = 100
+)
+
// ServePackage handles requests for the v1 package metadata endpoint.
func ServePackage(w http.ResponseWriter, r *http.Request, ds internal.DataSource) (err error) {
defer derrors.Wrap(&err, "ServePackage")
@@ -206,6 +213,7 @@ func ServeModule(w http.ResponseWriter, r *http.Request, ds internal.DataSource)
defer derrors.Wrap(&err, "ServeModule")
modulePath := strings.TrimPrefix(r.URL.Path, "/v1/module/")
+ modulePath = strings.Trim(modulePath, "/")
if modulePath == "" {
return serveErrorJSON(w, http.StatusBadRequest, "missing module path", nil)
}
@@ -339,6 +347,51 @@ func ServeModulePackages(w http.ResponseWriter, r *http.Request, ds internal.Dat
return serveJSON(w, http.StatusOK, resp)
}
+// ServeSearch handles requests for the v1 search endpoint.
+func ServeSearch(w http.ResponseWriter, r *http.Request, ds internal.DataSource) (err error) {
+ defer derrors.Wrap(&err, "ServeSearch")
+
+ var params SearchParams
+ if err := ParseParams(r.URL.Query(), &params); err != nil {
+ return serveErrorJSON(w, http.StatusBadRequest, err.Error(), nil)
+ }
+
+ if params.Query == "" {
+ return serveErrorJSON(w, http.StatusBadRequest, "missing query", nil)
+ }
+
+ dbresults, err := ds.Search(r.Context(), params.Query, internal.SearchOptions{
+ MaxResults: maxSearchResults,
+ SearchSymbols: params.Symbol != "",
+ SymbolFilter: params.Symbol,
+ })
+ if err != nil {
+ return err
+ }
+
+ var results []SearchResult
+ for _, r := range dbresults {
+ if params.Filter != "" {
+ if !strings.Contains(r.Synopsis, params.Filter) && !strings.Contains(r.PackagePath, params.Filter) {
+ continue
+ }
+ }
+ results = append(results, SearchResult{
+ PackagePath: r.PackagePath,
+ ModulePath: r.ModulePath,
+ Version: r.Version,
+ Synopsis: r.Synopsis,
+ })
+ }
+
+ resp, err := paginate(results, params.ListParams, searchResultsPerPage)
+ if err != nil {
+ return serveErrorJSON(w, http.StatusBadRequest, err.Error(), nil)
+ }
+
+ return serveJSON(w, http.StatusOK, resp)
+}
+
// needsResolution reports whether the version string is a sentinel like "latest" or "master".
func needsResolution(v string) bool {
return v == version.Latest || v == version.Master || v == version.Main
@@ -363,6 +416,9 @@ func serveErrorJSON(w http.ResponseWriter, status int, message string, candidate
})
}
+// paginate returns a paginated response for the given list of items and pagination parameters.
+// It uses offset-based pagination with a token that encodes the offset.
+// The default limit is used if the provided limit is non-positive.
func paginate[T any](all []T, lp ListParams, defaultLimit int) (PaginatedResponse[T], error) {
limit := lp.Limit
if limit <= 0 {
@@ -381,10 +437,7 @@ func paginate[T any](all []T, lp ListParams, defaultLimit int) (PaginatedRespons
if offset > len(all) {
offset = len(all)
}
- end := offset + limit
- if end > len(all) {
- end = len(all)
- }
+ end := min(offset+limit, len(all))
var nextToken string
if end < len(all) {