/* Package api exposes the main API engine. All HTTP APIs are handled here - so-called "business logic" should be here, or in a dedicated package (if that logic is complex enough). To use this package, you should create a new instance with New() passing a valid Config. The resulting Router will have the Router.Handler() function that returns a handler that can be used in a http.Server (or in other middlewares). Example: // Create the API router apirouter, err := api.New(api.Config{ Logger: logger, Database: appdb, }) if err != nil { logger.WithError(err).Error("error creating the API server instance") return fmt.Errorf("error creating the API server instance: %w", err) } router := apirouter.Handler() // ... other stuff here, like middleware chaining, etc. // Create the API server apiserver := http.Server{ Addr: cfg.Web.APIHost, Handler: router, ReadTimeout: cfg.Web.ReadTimeout, ReadHeaderTimeout: cfg.Web.ReadTimeout, WriteTimeout: cfg.Web.WriteTimeout, } // Start the service listening for requests in a separate goroutine apiserver.ListenAndServe() See the `main.go` file inside the `cmd/webapi` for a full usage example. */ package api import ( "errors" "net/http" "github.com/julienschmidt/httprouter" "github.com/notherealmarco/WASAPhoto/service/database" "github.com/sirupsen/logrus" ) // Config is used to provide dependencies and configuration to the New function. type Config struct { // Logger where log entries are sent Logger logrus.FieldLogger // Database is the instance of database.AppDatabase where data are saved Database database.AppDatabase DataPath string } // Router is the package API interface representing an API handler builder type Router interface { // Handler returns an HTTP handler for APIs provided in this package Handler() http.Handler // Close terminates any resource used in the package Close() error } // New returns a new Router instance func New(cfg Config) (Router, error) { // Check if the configuration is correct if cfg.Logger == nil { return nil, errors.New("logger is required") } if cfg.Database == nil { return nil, errors.New("database is required") } // Create a new router where we will register HTTP endpoints. The server will pass requests to this router to be // handled. router := httprouter.New() router.RedirectTrailingSlash = false router.RedirectFixedPath = false return &_router{ router: router, baseLogger: cfg.Logger, db: cfg.Database, dataPath: cfg.DataPath, }, nil } type _router struct { router *httprouter.Router // baseLogger is a logger for non-requests contexts, like goroutines or background tasks not started by a request. // Use context logger if available (e.g., in requests) instead of this logger. baseLogger logrus.FieldLogger db database.AppDatabase dataPath string }