diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c02ce1..11af348 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Changed + +- Default max page size is now 200. + +### Added + +- Added a flag --max-page-size to server subcommand to set the max page size. + ## [2.1.0](https://github.com/coder/code-marketplace/releases/tag/v2.1.0) - 2023-12-21 ### Changed diff --git a/api/api.go b/api/api.go index a06381e..0d4bbee 100644 --- a/api/api.go +++ b/api/api.go @@ -4,6 +4,7 @@ import ( "encoding/json" "net/http" "os" + "strconv" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" @@ -15,6 +16,8 @@ import ( "github.com/coder/code-marketplace/storage" ) +const MaxPageSizeDefault int = 200 + // QueryRequest implements an untyped object. It is the data sent to the API to // query for extensions. // https://github.com/microsoft/vscode/blob/a69f95fdf3dc27511517eef5ff62b21c7a418015/src/vs/platform/extensionManagement/common/extensionGalleryService.ts#L338-L342 @@ -55,14 +58,16 @@ type Options struct { Database database.Database Logger slog.Logger // Set to <0 to disable. - RateLimit int - Storage storage.Storage + RateLimit int + Storage storage.Storage + MaxPageSize int } type API struct { - Database database.Database - Handler http.Handler - Logger slog.Logger + Database database.Database + Handler http.Handler + Logger slog.Logger + MaxPageSize int } // New creates a new API server. @@ -71,6 +76,10 @@ func New(options *Options) *API { options.RateLimit = 512 } + if options.MaxPageSize == 0 { + options.MaxPageSize = MaxPageSizeDefault + } + r := chi.NewRouter() r.Use( @@ -84,9 +93,10 @@ func New(options *Options) *API { ) api := &API{ - Database: options.Database, - Handler: r, - Logger: options.Logger, + Database: options.Database, + Handler: r, + Logger: options.Logger, + MaxPageSize: options.MaxPageSize, } r.Get("/", func(rw http.ResponseWriter, r *http.Request) { @@ -163,10 +173,10 @@ func (api *API) extensionQuery(rw http.ResponseWriter, r *http.Request) { }) } for _, filter := range query.Filters { - if filter.PageSize < 0 || filter.PageSize > 50 { + if filter.PageSize < 0 || filter.PageSize > api.MaxPageSize { httpapi.Write(rw, http.StatusBadRequest, httpapi.ErrorResponse{ - Message: "Invalid page size", - Detail: "Check that the page size is between zero and fifty", + Message: "The page size must be between 0 and " + strconv.Itoa(api.MaxPageSize), + Detail: "Contact an administrator to increase the page size", RequestID: httpmw.RequestID(r), }) } diff --git a/api/api_test.go b/api/api_test.go index f511577..62b9144 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -119,8 +119,8 @@ func TestAPI(t *testing.T) { }}, }, Response: &httpapi.ErrorResponse{ - Message: "Invalid page size", - Detail: "Check that the page size is between zero and fifty", + Message: "The page size must be between 0 and 200", + Detail: "Contact an administrator to increase the page size", }, }, { @@ -255,9 +255,10 @@ func TestAPI(t *testing.T) { logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true}).Leveled(slog.LevelDebug) apiServer := api.New(&api.Options{ - Database: testutil.NewMockDB(exts), - Storage: testutil.NewMockStorage(), - Logger: logger, + Database: testutil.NewMockDB(exts), + Storage: testutil.NewMockStorage(), + Logger: logger, + MaxPageSize: api.MaxPageSizeDefault, }) server := httptest.NewServer(apiServer.Handler) diff --git a/cli/server.go b/cli/server.go index d8a03fb..befc20b 100644 --- a/cli/server.go +++ b/cli/server.go @@ -28,6 +28,7 @@ func server() *cobra.Command { extdir string repo string listcacheduration time.Duration + maxpagesize int ) cmd := &cobra.Command{ @@ -85,9 +86,10 @@ func server() *cobra.Command { // Start the API server. mapi := api.New(&api.Options{ - Database: database, - Storage: store, - Logger: logger, + Database: database, + Storage: store, + Logger: logger, + MaxPageSize: maxpagesize, }) server := &http.Server{ Handler: mapi.Handler, @@ -136,6 +138,7 @@ func server() *cobra.Command { } cmd.Flags().StringVar(&extdir, "extensions-dir", "", "The path to extensions.") + cmd.Flags().IntVar(&maxpagesize, "max-page-size", api.MaxPageSizeDefault, "The maximum number of pages to request") cmd.Flags().StringVar(&artifactory, "artifactory", "", "Artifactory server URL.") cmd.Flags().StringVar(&repo, "repo", "", "Artifactory repository.") cmd.Flags().StringVar(&address, "address", "127.0.0.1:3001", "The address on which to serve the marketplace API.") diff --git a/storage/local.go b/storage/local.go index 1033de1..363eae2 100644 --- a/storage/local.go +++ b/storage/local.go @@ -27,7 +27,7 @@ type Local struct { } type LocalOptions struct { - // How long to cache the list of extensions with their manifests. Zero means + // How long to cache the list of extensions with their manifests. Zero means // no cache. ListCacheDuration time.Duration ExtDir string