feat: add a new REST endpoint - GET /api/v1/user
This commit is contained in:
parent
037619cae2
commit
87da75847d
|
@ -15,6 +15,9 @@ import (
|
|||
"gitea.dwysokinski.me/twhelp/sessions/cmd/sessions/internal"
|
||||
"gitea.dwysokinski.me/twhelp/sessions/internal/bundb"
|
||||
"gitea.dwysokinski.me/twhelp/sessions/internal/router/meta"
|
||||
"gitea.dwysokinski.me/twhelp/sessions/internal/router/rest"
|
||||
"gitea.dwysokinski.me/twhelp/sessions/internal/service"
|
||||
"github.com/kelseyhightower/envconfig"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
|
@ -80,10 +83,38 @@ type serverConfig struct {
|
|||
}
|
||||
|
||||
func newServer(cfg serverConfig) (*http.Server, error) {
|
||||
apiCfg, err := newAPIConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("newAPIConfig: %w", err)
|
||||
}
|
||||
|
||||
// repos
|
||||
userRepo := bundb.NewUser(cfg.db)
|
||||
apiKeyRepo := bundb.NewAPIKey(cfg.db)
|
||||
|
||||
// services
|
||||
userSvc := service.NewUser(userRepo)
|
||||
apiKeySvc := service.NewAPIKey(apiKeyRepo, userSvc)
|
||||
|
||||
// router
|
||||
r := chi.NewRouter()
|
||||
r.Use(getChiMiddlewares(cfg.logger)...)
|
||||
r.Mount(metaEndpointsPrefix, meta.NewRouter([]meta.Checker{bundb.NewChecker(cfg.db)}))
|
||||
r.Mount("/api", rest.NewRouter(rest.RouterConfig{
|
||||
APIKeyVerifier: apiKeySvc,
|
||||
CORS: rest.CORSConfig{
|
||||
Enabled: apiCfg.CORSEnabled,
|
||||
AllowedOrigins: apiCfg.CORSAllowedOrigins,
|
||||
AllowedMethods: apiCfg.CORSAllowedMethods,
|
||||
AllowCredentials: apiCfg.CORSAllowCredentials,
|
||||
MaxAge: int(apiCfg.CORSMaxAge),
|
||||
},
|
||||
Swagger: rest.SwaggerConfig{
|
||||
Enabled: apiCfg.SwaggerEnabled,
|
||||
Host: apiCfg.SwaggerHost,
|
||||
Schemes: apiCfg.SwaggerSchemes,
|
||||
},
|
||||
}))
|
||||
|
||||
return &http.Server{
|
||||
Addr: ":" + defaultPort,
|
||||
|
@ -95,6 +126,25 @@ func newServer(cfg serverConfig) (*http.Server, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
type apiConfig struct {
|
||||
SwaggerEnabled bool `envconfig:"SWAGGER_ENABLED" default:"true"`
|
||||
SwaggerHost string `envconfig:"SWAGGER_HOST" default:""`
|
||||
SwaggerSchemes []string `envconfig:"SWAGGER_SCHEMES" default:"http,https"`
|
||||
CORSEnabled bool `envconfig:"CORS_ENABLED" default:"false"`
|
||||
CORSAllowedOrigins []string `envconfig:"CORS_ALLOWED_ORIGINS" default:""`
|
||||
CORSAllowCredentials bool `envconfig:"CORS_ALLOW_CREDENTIALS" default:"false"`
|
||||
CORSAllowedMethods []string `envconfig:"CORS_ALLOWED_METHODS" default:"HEAD,GET"`
|
||||
CORSMaxAge uint32 `envconfig:"CORS_MAX_AGE" default:"300"`
|
||||
}
|
||||
|
||||
func newAPIConfig() (apiConfig, error) {
|
||||
var cfg apiConfig
|
||||
if err := envconfig.Process("API", &cfg); err != nil {
|
||||
return apiConfig{}, fmt.Errorf("envconfig.Process: %w", err)
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func getChiMiddlewares(logger *zap.Logger) chi.Middlewares {
|
||||
return chi.Middlewares{
|
||||
middleware.RealIP,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package model
|
||||
|
||||
type APIError struct {
|
||||
Code string `json:"code" enums:"entity-not-found,route-not-found,method-not-allowed,validation-error,already-exists,internal-server-error"`
|
||||
Code string `json:"code" enums:"entity-not-found,route-not-found,method-not-allowed,validation-error,unauthorized,already-exists,internal-server-error"`
|
||||
Message string `json:"message"`
|
||||
} // @name ApiError
|
||||
|
||||
|
|
|
@ -12,3 +12,7 @@ package rest
|
|||
// @BasePath /api/v1
|
||||
|
||||
// @query.collection.format multi
|
||||
|
||||
// @securityDefinitions.apikey ApiKeyAuth
|
||||
// @in header
|
||||
// @name X-Api-Key
|
||||
|
|
|
@ -44,8 +44,6 @@ type RouterConfig struct {
|
|||
func NewRouter(cfg RouterConfig) *chi.Mux {
|
||||
router := chi.NewRouter()
|
||||
|
||||
router.Use(authMiddleware(cfg.APIKeyVerifier))
|
||||
|
||||
if cfg.CORS.Enabled {
|
||||
router.Use(cors.Handler(cors.Options{
|
||||
AllowedOrigins: cfg.CORS.AllowedOrigins,
|
||||
|
@ -65,6 +63,14 @@ func NewRouter(cfg RouterConfig) *chi.Mux {
|
|||
docs.SwaggerInfo.Schemes = cfg.Swagger.Schemes
|
||||
r.Get("/swagger/*", httpSwagger.Handler())
|
||||
}
|
||||
|
||||
r.Route("/", func(r chi.Router) {
|
||||
r.Use(authMiddleware(cfg.APIKeyVerifier))
|
||||
|
||||
r.Get("/user", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
return router
|
||||
|
@ -93,17 +99,28 @@ func authMiddleware(verifier APIKeyVerifier) func(http.Handler) http.Handler {
|
|||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
key := r.Header.Get("X-API-Key")
|
||||
if key == "" {
|
||||
next.ServeHTTP(w, r)
|
||||
renderJSON(w, http.StatusUnauthorized, model.ErrorResp{
|
||||
Error: model.APIError{
|
||||
Code: "unauthorized",
|
||||
Message: "invalid API key",
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
user, err := verifier.Verify(r.Context(), key)
|
||||
if err != nil {
|
||||
next.ServeHTTP(w, r)
|
||||
renderJSON(w, http.StatusUnauthorized, model.ErrorResp{
|
||||
Error: model.APIError{
|
||||
Code: "unauthorized",
|
||||
Message: "invalid API key",
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(user)
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ spec:
|
|||
value: "10"
|
||||
- name: DB_MAX_IDLE_CONNECTIONS
|
||||
value: "5"
|
||||
- name: API_SWAGGER_ENABLED
|
||||
value: "true"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /_meta/livez
|
||||
|
|
Loading…
Reference in New Issue