diff options
| author | Ethan Lee <ethanalee@google.com> | 2026-03-24 15:29:27 +0000 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2026-03-31 12:06:07 -0700 |
| commit | 50f3e086f52d8af852dacd214738f8f83a9007aa (patch) | |
| tree | 3cf980b0797cfe39cf4814eed64f928e6e2a8bec /internal | |
| parent | 553cc7bbf577a297ad6e78870316bdf5e4c19e04 (diff) | |
| download | go-x-pkgsite-50f3e086f52d8af852dacd214738f8f83a9007aa.tar.xz | |
internal/api: centralize pagination and trimming logic
- All handlers returning lists will utilize the paginate helper.
- Path trimming logic has also been modularized within a helper.
Change-Id: I5c99ae8264ea76587137e29524ad19795652e43b
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/758642
Auto-Submit: Ethan Lee <ethanalee@google.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
kokoro-CI: kokoro <noreply+kokoro@google.com>
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/api/api.go | 71 | ||||
| -rw-r--r-- | internal/api/api_test.go | 24 |
2 files changed, 48 insertions, 47 deletions
diff --git a/internal/api/api.go b/internal/api/api.go index 60549f00..62e5663f 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -31,9 +31,7 @@ const ( func ServePackage(w http.ResponseWriter, r *http.Request, ds internal.DataSource) (err error) { defer derrors.Wrap(&err, "ServePackage") - // The path is expected to be /v1/package/{path} - pkgPath := strings.TrimPrefix(r.URL.Path, "/v1/package/") - pkgPath = strings.Trim(pkgPath, "/") + pkgPath := trimPath(r, "/v1/package/") if pkgPath == "" { return serveErrorJSON(w, http.StatusBadRequest, "missing package path", nil) } @@ -157,8 +155,7 @@ func ServePackage(w http.ResponseWriter, r *http.Request, ds internal.DataSource func ServeModule(w http.ResponseWriter, r *http.Request, ds internal.DataSource) (err error) { defer derrors.Wrap(&err, "ServeModule") - modulePath := strings.TrimPrefix(r.URL.Path, "/v1/module/") - modulePath = strings.Trim(modulePath, "/") + modulePath := trimPath(r, "/v1/module/") if modulePath == "" { return serveErrorJSON(w, http.StatusBadRequest, "missing module path", nil) } @@ -210,7 +207,7 @@ func ServeModule(w http.ResponseWriter, r *http.Request, ds internal.DataSource) func ServeModuleVersions(w http.ResponseWriter, r *http.Request, ds internal.DataSource) (err error) { defer derrors.Wrap(&err, "ServeModuleVersions") - path := strings.TrimPrefix(r.URL.Path, "/v1/versions/") + path := trimPath(r, "/v1/versions/") if path == "" { return serveErrorJSON(w, http.StatusBadRequest, "missing path", nil) } @@ -240,7 +237,7 @@ func ServeModuleVersions(w http.ResponseWriter, r *http.Request, ds internal.Dat func ServeModulePackages(w http.ResponseWriter, r *http.Request, ds internal.DataSource) (err error) { defer derrors.Wrap(&err, "ServeModulePackages") - modulePath := strings.TrimPrefix(r.URL.Path, "/v1/packages/") + modulePath := trimPath(r, "/v1/packages/") if modulePath == "" { return serveErrorJSON(w, http.StatusBadRequest, "missing module path", nil) } @@ -265,16 +262,8 @@ func ServeModulePackages(w http.ResponseWriter, r *http.Request, ds internal.Dat // TODO: Handle params.Token and params.Filter. // For now, we just use params.Limit to limit the number of packages returned. - limit := params.Limit - if limit <= 0 { - limit = 100 - } - if limit > len(metas) { - limit = len(metas) - } - var items []Package - for _, m := range metas[:limit] { + for _, m := range metas { items = append(items, Package{ Path: m.Path, ModulePath: modulePath, @@ -284,9 +273,9 @@ func ServeModulePackages(w http.ResponseWriter, r *http.Request, ds internal.Dat }) } - resp := PaginatedResponse[Package]{ - Items: items, - Total: len(metas), + resp, err := paginate(items, params.ListParams, 100) + if err != nil { + return serveErrorJSON(w, http.StatusBadRequest, err.Error(), nil) } return serveJSON(w, http.StatusOK, resp) @@ -341,8 +330,7 @@ func ServeSearch(w http.ResponseWriter, r *http.Request, ds internal.DataSource) func ServePackageSymbols(w http.ResponseWriter, r *http.Request, ds internal.DataSource) (err error) { defer derrors.Wrap(&err, "ServePackageSymbols") - pkgPath := strings.TrimPrefix(r.URL.Path, "/v1/symbols/") - pkgPath = strings.Trim(pkgPath, "/") + pkgPath := trimPath(r, "/v1/symbols/") if pkgPath == "" { return serveErrorJSON(w, http.StatusBadRequest, "missing package path", nil) } @@ -372,16 +360,8 @@ func ServePackageSymbols(w http.ResponseWriter, r *http.Request, ds internal.Dat return err } - limit := params.Limit - if limit <= 0 { - limit = 100 - } - if limit > len(syms) { - limit = len(syms) - } - var items []Symbol - for _, s := range syms[:limit] { + for _, s := range syms { items = append(items, Symbol{ ModulePath: um.ModulePath, Version: um.Version, @@ -392,9 +372,9 @@ func ServePackageSymbols(w http.ResponseWriter, r *http.Request, ds internal.Dat }) } - resp := PaginatedResponse[Symbol]{ - Items: items, - Total: len(syms), + resp, err := paginate(items, params.ListParams, 100) + if err != nil { + return serveErrorJSON(w, http.StatusBadRequest, err.Error(), nil) } return serveJSON(w, http.StatusOK, resp) @@ -404,7 +384,7 @@ func ServePackageSymbols(w http.ResponseWriter, r *http.Request, ds internal.Dat func ServePackageImportedBy(w http.ResponseWriter, r *http.Request, ds internal.DataSource) (err error) { defer derrors.Wrap(&err, "ServePackageImportedBy") - pkgPath := strings.TrimPrefix(r.URL.Path, "/v1/imported-by/") + pkgPath := trimPath(r, "/v1/imported-by/") if pkgPath == "" { return serveErrorJSON(w, http.StatusBadRequest, "missing package path", nil) } @@ -466,7 +446,7 @@ func ServeVulnerabilities(vc *vuln.Client) func(w http.ResponseWriter, r *http.R return func(w http.ResponseWriter, r *http.Request, ds internal.DataSource) (err error) { defer derrors.Wrap(&err, "ServeVulnerabilities") - modulePath := strings.TrimPrefix(r.URL.Path, "/v1/vulns/") + modulePath := trimPath(r, "/v1/vulns/") if modulePath == "" { return serveErrorJSON(w, http.StatusBadRequest, "missing module path", nil) } @@ -489,31 +469,28 @@ func ServeVulnerabilities(vc *vuln.Client) func(w http.ResponseWriter, r *http.R // Passing an empty packagePath gets all vulns for the module. vulns := vuln.VulnsForPackage(r.Context(), modulePath, requestedVersion, "", vc) - limit := params.Limit - if limit <= 0 { - limit = 100 - } - if limit > len(vulns) { - limit = len(vulns) - } - var items []Vulnerability - for _, v := range vulns[:limit] { + for _, v := range vulns { items = append(items, Vulnerability{ ID: v.ID, Details: v.Details, }) } - resp := PaginatedResponse[Vulnerability]{ - Items: items, - Total: len(vulns), + resp, err := paginate(items, params.ListParams, 100) + if err != nil { + return serveErrorJSON(w, http.StatusBadRequest, err.Error(), nil) } return serveJSON(w, http.StatusOK, resp) } } +func trimPath(r *http.Request, prefix string) string { + path := strings.TrimPrefix(r.URL.Path, prefix) + return strings.Trim(path, "/") +} + // resolveModulePath determines the correct module path for a given package path and version. // If the module path is not provided, it searches through potential candidate module paths // derived from the package path. If multiple valid modules contain the package, it returns diff --git a/internal/api/api_test.go b/internal/api/api_test.go index 0bc409c5..9930e3c9 100644 --- a/internal/api/api_test.go +++ b/internal/api/api_test.go @@ -399,12 +399,30 @@ func TestServeModulePackages(t *testing.T) { url string wantStatus int wantCount int + wantTotal int + wantToken string }{ { name: "all packages", url: "/v1/packages/example.com?version=v1.0.0", wantStatus: http.StatusOK, wantCount: 2, + wantTotal: 2, + }, + { + name: "limit and token", + url: "/v1/packages/example.com?version=v1.0.0&limit=1", + wantStatus: http.StatusOK, + wantCount: 1, + wantTotal: 2, + wantToken: "1", + }, + { + name: "next page", + url: "/v1/packages/example.com?version=v1.0.0&limit=1&token=1", + wantStatus: http.StatusOK, + wantCount: 1, + wantTotal: 2, }, } { t.Run(test.name, func(t *testing.T) { @@ -428,6 +446,12 @@ func TestServeModulePackages(t *testing.T) { if len(got.Items) != test.wantCount { t.Errorf("count = %d, want %d", len(got.Items), test.wantCount) } + if got.Total != test.wantTotal { + t.Errorf("total = %d, want %d", got.Total, test.wantTotal) + } + if got.NextPageToken != test.wantToken { + t.Errorf("token = %q, want %q", got.NextPageToken, test.wantToken) + } } }) } |
