experiment: successfully implemented dependency injections for controllers and services

This commit is contained in:
2025-06-20 16:14:55 +03:00
parent 654c1eb7b5
commit aab55a143f
10 changed files with 208 additions and 156 deletions

View File

@@ -1,50 +1,31 @@
package controllers
import (
"easywish/internal/models"
"easywish/internal/services"
"net/http"
"github.com/gin-gonic/gin"
)
// @Summary Register an account
// @Tags Auth
// @Accept json
// @Produce json
// @Router /auth/registrationBegin [post]
func RegistrationBegin(c *gin.Context) {
var request models.RegistrationBeginRequest
if err := c.ShouldBindJSON(&request); err != nil {
c.Status(http.StatusBadRequest)
return
}
auths := services.NewAuthService()
result, err := auths.Login(request)
if err != nil {
c.Status(http.StatusTeapot)
return
}
c.JSON(http.StatusFound, result)
c.Status(http.StatusNotImplemented)
type AuthController interface {
RegistrationBegin(c *gin.Context)
RegistrationComplete(c *gin.Context)
Login(c *gin.Context)
Refresh(c *gin.Context)
PasswordResetBegin(c *gin.Context)
PasswordResetComplete(c *gin.Context)
Router
}
// @Summary Confirm with code, finish creating the account
// @Tags Auth
// @Accept json
// @Produce json
// @Router /auth/registrationComplete [post]
func RegistrationComplete(c *gin.Context) {
c.Status(http.StatusNotImplemented)
type authControllerImpl struct {
authService services.AuthService
}
func NewAuthController(as services.AuthService) AuthController {
return &authControllerImpl{authService: as}
}
// Login implements AuthController.
// @Summary Acquire tokens via login credentials (and 2FA code if needed)
// @Tags Auth
// @Accept json
@@ -52,50 +33,65 @@ func RegistrationComplete(c *gin.Context) {
// @Param request body models.LoginRequest true "desc"
// @Success 200 {object} models.LoginResponse "desc"
// @Router /auth/login [post]
func Login(c *gin.Context) {
var request models.LoginRequest
if err := c.ShouldBindJSON(&request); err != nil {
c.Status(http.StatusBadRequest)
return
}
auths := services.NewAuthService()
result, err := auths.Login(request)
if err != nil {
c.Status(http.StatusTeapot)
return
}
c.JSON(http.StatusFound, result)
}
// @Summary Receive new tokens via refresh token
// @Tags Auth
// @Accept json
// @Produce json
// @Router /auth/refresh [post]
func Refresh(c *gin.Context) {
func (a *authControllerImpl) Login(c *gin.Context) {
c.Status(http.StatusNotImplemented)
}
// PasswordResetBegin implements AuthController.
// @Summary Request password reset email
// @Tags Auth
// @Accept json
// @Produce json
// @Router /auth/passwordResetBegin [post]
func PasswordResetBegin(c *gin.Context) {
func (a *authControllerImpl) PasswordResetBegin(c *gin.Context) {
c.Status(http.StatusNotImplemented)
}
// PasswordResetComplete implements AuthController.
// @Summary Complete password reset with email code and provide 2FA code or backup code if needed
// @Tags Auth
// @Accept json
// @Produce json
// @Router /auth/passwordResetComplete [post]
func PasswordResetComplete(c *gin.Context) {
func (a *authControllerImpl) PasswordResetComplete(c *gin.Context) {
c.Status(http.StatusNotImplemented)
}
// Refresh implements AuthController.
// @Summary Receive new tokens via refresh token
// @Tags Auth
// @Accept json
// @Produce json
// @Router /auth/refresh [post]
func (a *authControllerImpl) Refresh(c *gin.Context) {
c.Status(http.StatusNotImplemented)
}
// RegistrationComplete implements AuthController.
// @Summary Register an account
// @Tags Auth
// @Accept json
// @Produce json
// @Router /auth/registrationBegin [post]
func (a *authControllerImpl) RegistrationBegin(c *gin.Context) {
c.Status(http.StatusNotImplemented)
}
// RegistrationBegin implements AuthController.
// @Summary Confirm with code, finish creating the account
// @Tags Auth
// @Accept json
// @Produce json
// @Router /auth/registrationComplete [post]
func (a *authControllerImpl) RegistrationComplete(c *gin.Context) {
c.Status(http.StatusNotImplemented)
}
func (a *authControllerImpl) RegisterRoutes(group *gin.RouterGroup) {
group.POST("/registrationBegin", a.RegistrationBegin)
group.POST("/registrationComplete", a.RegistrationComplete)
group.POST("/login", a.Login)
group.POST("/refresh", a.Refresh)
group.POST("/passwordResetBegin", a.PasswordResetBegin)
group.POST("/passwordResetComplete", a.PasswordResetComplete)
}

View File

@@ -0,0 +1,9 @@
package controllers
import (
"github.com/gin-gonic/gin"
)
type Router interface {
RegisterRoutes(group *gin.RouterGroup)
}

View File

@@ -6,10 +6,18 @@ import (
"github.com/gin-gonic/gin"
)
type HealthStatus struct {
Healthy bool `json:"healthy"`
type ServiceController interface {
HealthCheck(c *gin.Context)
Router
}
type serviceControllerImpl struct{}
func NewServiceController() ServiceController {
return &serviceControllerImpl{}
}
// HealthCheck implements ServiceController.
// @Summary Get health status
// @Description Used internally for checking service health
// @Tags Service
@@ -17,6 +25,15 @@ type HealthStatus struct {
// @Produce json
// @Success 200 {object} HealthStatus "Says whether it's healthy or not"
// @Router /service/health [get]
func HealthCheck(c *gin.Context) {
func (s *serviceControllerImpl) HealthCheck(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"healthy": true})
}
// RegisterRoutes implements ServiceController.
func (s *serviceControllerImpl) RegisterRoutes(group *gin.RouterGroup) {
group.GET("/health", s.HealthCheck)
}
type HealthStatus struct {
Healthy bool `json:"healthy"`
}

View File

@@ -0,0 +1,39 @@
package routes
import (
"easywish/internal/controllers"
"github.com/gin-gonic/gin"
)
func NewRouter(engine *gin.Engine, groups []RouteGroup) *gin.Engine {
apiGroup := engine.Group("/api")
for _, group := range groups {
subgroup := apiGroup.Group(group.BasePath)
subgroup.Use(group.Middleware...)
group.Router.RegisterRoutes(subgroup)
}
return engine
}
type RouteGroup struct {
BasePath string
Middleware []gin.HandlerFunc
Router controllers.Router
}
func NewRouteGroups(
authController controllers.AuthController,
serviceController controllers.ServiceController,
) []RouteGroup {
return []RouteGroup{
{
BasePath: "/auth",
Router: authController,
},
{
BasePath: "/service",
Router: serviceController,
},
}
}

View File

@@ -1,52 +1,12 @@
package routes
import (
"easywish/internal/controllers"
"easywish/internal/middleware"
"github.com/gin-gonic/gin"
"go.uber.org/fx"
)
func SetupRoutes(r *gin.Engine) *gin.Engine {
apiGroup := r.Group("/api")
{
serviceGroup := apiGroup.Group("/service")
{
serviceGroup.GET("/health", controllers.HealthCheck)
}
authGroup := apiGroup.Group("/auth")
{
authGroup.POST("/registrationBegin", controllers.RegistrationBegin)
authGroup.POST("/registrationComplete", controllers.RegistrationComplete)
authGroup.POST("/login", controllers.Login)
authGroup.POST("/refresh", controllers.Refresh)
authGroup.POST("/passwordResetBegin", controllers.PasswordResetBegin)
authGroup.POST("/passwordResetComplete", controllers.PasswordResetComplete)
}
profileGroup := apiGroup.Group("/profile")
{
profileGroup.GET("/:username", controllers.GetProfile)
}
protected := apiGroup.Group("")
protected.Use(middleware.JWTAuthMiddleware())
{
accountGroup := protected.Group("/account")
{
accountGroup.PUT("/changePassword", controllers.ChangePassword)
}
profileGroup := protected.Group("/profile")
{
profileGroup.GET("/me", controllers.GetOwnProfile)
profileGroup.GET("/privacy", controllers.GetPrivacySettings)
profileGroup.PATCH("/privacy", controllers.UpdatePrivacySettings)
}
}
}
return r
}
var Module = fx.Module("routes",
fx.Provide(
NewRouteGroups,
),
fx.Invoke(NewRouter),
)

View File

@@ -2,7 +2,6 @@ package services
import (
"easywish/internal/database"
"easywish/internal/errors"
errs "easywish/internal/errors"
"easywish/internal/models"
"easywish/internal/utils"
@@ -23,32 +22,11 @@ func NewAuthService() AuthService {
}
func (a *authServiceImpl) RegistrationBegin(request models.RegistrationBeginRequest) (bool, error) {
conn, ctx, err := utils.GetDbConn()
if err != nil {
return false, err
}
defer conn.Close(ctx)
queries := database.New(conn)
tx, err := database.Begin()
if err != nil {
return err
}
defer tx.Rollback()
qtx := queries.WithTx(tx)
tx.Commit()
return
return false, errs.ErrNotImplemented
}
func (a *authServiceImpl) RegistrationComplete(request models.RegistrationBeginRequest) (*models.RegistrationCompleteResponse, error) {
conn, ctx, err := utils.GetDbConn()
if err != nil {
return nil, err
}
defer conn.Close(ctx)
return nil, errs.ErrNotImplemented
}
func (a *authServiceImpl) Login(request models.LoginRequest) (*models.LoginResponse, error) {
@@ -75,5 +53,5 @@ func (a *authServiceImpl) Login(request models.LoginRequest) (*models.LoginRespo
}
func (a *authServiceImpl) Refresh(request models.RefreshRequest) (*models.RefreshResponse, error) {
return nil, errors.ErrNotImplemented
return nil, errs.ErrNotImplemented
}

View File

@@ -0,0 +1,12 @@
package services
import (
"go.uber.org/fx"
)
var Module = fx.Module("services",
fx.Provide(
NewAuthService,
),
)