Răsfoiți Sursa

FIRST COMMIT

cesarssh.dev@gmail.com 1 an în urmă
comite
04ebe70241

+ 32 - 0
Dockerfile

@@ -0,0 +1,32 @@
+# Usa una imagen base de Go
+FROM golang:1.23 AS builder
+
+# Establece el directorio de trabajo
+WORKDIR /app
+
+# Establece las variables de entorno necesarias para la construcción
+ENV GO111MODULE=on \
+    CGO_ENABLED=0 \
+    GOOS=linux \
+    GOARCH=amd64
+
+# Copia los archivos de módulo y descarga las dependencias
+COPY go.mod go.sum ./
+RUN go mod download
+
+# Copia el resto de los archivos y compila la aplicación
+COPY . .
+RUN go build -o main ./cmd/main.go
+
+# Usa una imagen base más ligera para ejecutar
+FROM alpine:latest
+
+# Copia el ejecutable desde la etapa de compilación
+WORKDIR /root/
+COPY --from=builder /app/main .
+
+# Expone el puerto que usará la aplicación
+EXPOSE 8080
+
+# Comando para ejecutar la aplicación
+CMD ["./main"]

+ 39 - 0
cmd/main.go

@@ -0,0 +1,39 @@
+package main
+
+import (
+	"log"
+	"net/http"
+
+	"api-dockerization/db"
+	"api-dockerization/internal/handlers"
+	"api-dockerization/internal/models"
+	"api-dockerization/internal/repository"
+	"api-dockerization/internal/service"
+	"api-dockerization/routes"
+
+	"github.com/gorilla/mux"
+)
+
+func main() {
+	//Conexion de la DB
+	db.DBConnection()
+
+	// Migrar el modelo
+	db.AutoMigrate(&models.User{})
+
+	// Inicializar repositorios y servicios
+	userRepo := repository.NewUserRepository(db.DB)
+
+	userCmdService := service.NewUserCommandService(userRepo)
+	userQryService := service.NewUserQueryService(userRepo)
+	userHandler := handlers.NewUserHandler(userCmdService, userQryService)
+
+	// Configurar el enrutador
+	r := mux.NewRouter()
+	// Registrar las rutas de usuarios
+	routes.SetupUserRoutes(r, userHandler)
+
+	// Iniciar el servidor
+	log.Println("API corriendo en :8080")
+	log.Fatal(http.ListenAndServe(":8080", r))
+}

+ 50 - 0
compose.yml

@@ -0,0 +1,50 @@
+version: '3.7'
+
+services:
+  app:
+    container_name: go-api
+    build:
+      context: .
+      dockerfile: Dockerfile
+    image: go-api
+    ports:
+      - 8080:8080
+    environment:
+      - DB_HOST=mysql
+      - DB_PORT=3306
+      - DB_USER=root
+      - DB_PASSWORD=password
+      - DB_NAME=mydbusers
+    depends_on:
+      mysql:
+        condition: service_healthy
+    networks:
+      - go-network
+
+  mysql:
+    container_name: go-mysql
+    image: mysql:latest
+    environment:
+      - MYSQL_ROOT_PASSWORD=password
+      - MYSQL_DATABASE=mydbusers
+
+    volumes:
+      - dbdata:/var/lib/mysql
+    ports:
+      - "3307:3306"
+
+    networks:
+      - go-network
+    healthcheck:
+      test: [ "CMD", "mysqladmin", "ping", "-h", "mysql" ]
+      interval: 10s
+      timeout: 5s
+      retries: 3
+
+volumes:
+  dbdata:
+
+
+networks: 
+  go-network:
+    driver: bridge

+ 42 - 0
db/anotherway.txt

@@ -0,0 +1,42 @@
+package db
+
+import (
+	"fmt"
+	"log"
+	"os"
+
+	"gorm.io/driver/mysql"
+	"gorm.io/gorm"
+)
+
+func getDSN() string {
+	return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
+		os.Getenv("DB_USER"),
+		os.Getenv("DB_PASSWORD"),
+		os.Getenv("DB_HOST"),
+		os.Getenv("DB_PORT"),
+		os.Getenv("DB_NAME"),
+	)
+}
+
+var DB *gorm.DB
+
+func DBConnection() {
+	var err error
+	DSN := getDSN()
+	DB, err = gorm.Open(mysql.Open(DSN), &gorm.Config{})
+
+	if err != nil {
+		log.Printf("Error al conectar a la base de datos: %v", err)
+		return // Manejar el error adecuadamente
+	}
+	log.Println("DB connected")
+}
+
+// AutoMigrate realiza la migración de los modelos
+func AutoMigrate(models ...interface{}) {
+	err := DB.AutoMigrate(models...)
+	if err != nil {
+		log.Fatal("Error al realizar la migration:", err)
+	}
+}

+ 38 - 0
db/connection.go

@@ -0,0 +1,38 @@
+package db
+
+import (
+	"log"
+
+	"gorm.io/driver/mysql"
+	"gorm.io/gorm"
+)
+
+// Config to connect mySQL
+var DSN = "root:password@tcp(mysql:3306)/mydbusers?charset=utf8mb4&parseTime=True&loc=Local"
+
+
+var DB *gorm.DB
+
+func DBConnection() {
+	var err error
+	DB, err = gorm.Open(mysql.Open(DSN), &gorm.Config{})
+
+	// if err != nil {
+	// 	log.Fatal(error)
+	// } else {
+	// 	log.Println("DB connected")
+	// }
+	if err != nil {
+		log.Printf("Error al conectar a la base de datos: %v", err)
+		return // Manejar el error adecuadamente
+	}
+	log.Println("DB connected")
+}
+
+// AutoMigrate realiza la migración de los modelos
+func AutoMigrate(models ...interface{}) {
+	err := DB.AutoMigrate(models...)
+	if err != nil {
+		log.Fatal("Error al realizar la migration:", err)
+	}
+}

+ 22 - 0
go.mod

@@ -0,0 +1,22 @@
+module api-dockerization
+
+go 1.23.1
+
+require (
+	filippo.io/edwards25519 v1.1.0 // indirect
+	github.com/gabriel-vasile/mimetype v1.4.3 // indirect
+	github.com/go-playground/locales v0.14.1 // indirect
+	github.com/go-playground/universal-translator v0.18.1 // indirect
+	github.com/go-playground/validator/v10 v10.22.1 // indirect
+	github.com/go-sql-driver/mysql v1.8.1 // indirect
+	github.com/gorilla/mux v1.8.1 // indirect
+	github.com/jinzhu/inflection v1.0.0 // indirect
+	github.com/jinzhu/now v1.1.5 // indirect
+	github.com/leodido/go-urn v1.4.0 // indirect
+	golang.org/x/crypto v0.19.0 // indirect
+	golang.org/x/net v0.21.0 // indirect
+	golang.org/x/sys v0.17.0 // indirect
+	golang.org/x/text v0.19.0 // indirect
+	gorm.io/driver/mysql v1.5.7 // indirect
+	gorm.io/gorm v1.25.12 // indirect
+)

+ 34 - 0
go.sum

@@ -0,0 +1,34 @@
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
+github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
+github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
+github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
+github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
+github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
+github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA=
+github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
+github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
+github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
+github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
+github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
+github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
+github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
+github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
+github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
+github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
+golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
+golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
+golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
+golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
+golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
+golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
+golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
+gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
+gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
+gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
+gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=

+ 12 - 0
info.txt

@@ -0,0 +1,12 @@
+#REPOS UTILIZADOS
+
+go get -u gorm.io/driver/mysql
+go get -u github.com/gorilla/mux
+go get github.com/go-playground/validator/v10
+
+#Comandos basicos
+docker-compose up --build
+docker-compose up -d
+docker-compose down
+docker exec -it go-mysql mysql -u root -p  //ENTRAR AQUI PARA INTERACTUAR CON LA BD
+go run cmd/main.go

+ 1 - 0
initdb/create_db.sql

@@ -0,0 +1 @@
+CREATE DATABASE IF NOT EXISTS mydbusers;

+ 51 - 0
internal/command/create_user_command.go

@@ -0,0 +1,51 @@
+package command
+
+import (
+	"api-dockerization/internal/models"
+	"errors"
+)
+
+type CreateUserCommand struct {
+	FirstName string `json:"first_name"`
+	LastName  string `json:"last_name"`
+	Sex       string `json:"sex"`
+	BirthDate string `json:"birth_date"`
+}
+
+func NewCreateUserCommand(firstName, lastName, sex, birthDate string) *CreateUserCommand {
+	return &CreateUserCommand{
+		FirstName: firstName,
+		LastName:  lastName,
+		Sex:       sex,
+		BirthDate: birthDate,
+	}
+}
+
+// Validate valida los campos del comando
+func (c *CreateUserCommand) Validate() error {
+	if c.FirstName == "" {
+		return errors.New("your firstname is required")
+	}
+	if c.LastName == "" {
+		return errors.New("your lastname is required")
+	}
+	if c.BirthDate == "" {
+		return errors.New("your birthdate is required")
+	}
+	if c.Sex == "" {
+		return errors.New("your sex is required")
+	}
+	// Crear una instancia de User para utilizar la validacion del modelo
+	user := models.User{
+		FirstName: c.FirstName,
+		LastName:  c.LastName,
+		Sex:       c.Sex,
+		BirthDate: c.BirthDate,
+	}
+
+	// Validar el modelo User
+	if err := user.Validate(); err != nil {
+		return err
+	}
+	return nil
+}

+ 9 - 0
internal/command/delete_user_command.go

@@ -0,0 +1,9 @@
+package command
+
+type DeleteUserCommand struct {
+	ID uint `json:"id"`
+}
+
+func NewDeleteUserCommand(id uint) *DeleteUserCommand {
+	return &DeleteUserCommand{ID: id}
+}

+ 123 - 0
internal/handlers/user_handler.go

@@ -0,0 +1,123 @@
+package handlers
+
+import (
+	"api-dockerization/internal/command"
+	"api-dockerization/internal/service"
+	"errors"
+	"strconv"
+
+	"encoding/json"
+	"net/http"
+
+	"github.com/gorilla/mux"
+	"gorm.io/gorm"
+)
+
+type UserHandler struct {
+	commandService *service.UserCommandService
+	queryService   *service.UserQueryService
+}
+
+func NewUserHandler(cmdService *service.UserCommandService, qryService *service.UserQueryService) *UserHandler {
+	return &UserHandler{
+		commandService: cmdService,
+		queryService:   qryService,
+	}
+}
+
+func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request) {
+	var cmd command.CreateUserCommand
+	if err := json.NewDecoder(r.Body).Decode(&cmd); err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
+		return
+	}
+	// Llamar a la validación
+	if err := cmd.Validate(); err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
+		return
+	}
+
+	if err := h.commandService.CreateUser(&cmd); err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+
+	w.WriteHeader(http.StatusCreated)
+	// Enviar un mensaje de éxito como respuesta
+	response := map[string]string{"message": "User created"}
+	json.NewEncoder(w).Encode(response)
+}
+
+func (h *UserHandler) GetUsers(w http.ResponseWriter, r *http.Request) {
+	users, err := h.queryService.GetUsers()
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+
+	w.Header().Set("Content-Type", "application/json")
+	json.NewEncoder(w).Encode(users)
+}
+
+func (h *UserHandler) GetUserById(w http.ResponseWriter, r *http.Request) {
+	vars := mux.Vars(r)   // Obtener las variables de la ruta
+	idParam := vars["id"] // Obtener el ID del usuario
+
+	// Convertir el ID a uint
+	id, err := strconv.ParseUint(idParam, 10, 32)
+	if err != nil {
+		http.Error(w, "Invalid user ID", http.StatusBadRequest)
+		return
+	}
+
+	// Obtener el usuario usando el servicio de consulta
+	user, err := h.queryService.GetUserById(uint(id))
+	if err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			http.Error(w, "User not found", http.StatusNotFound)
+		} else {
+			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+		}
+		return
+	}
+
+	// Configurar el tipo de contenido y codificar el usuario en JSON
+	w.Header().Set("Content-Type", "application/json")
+	if err := json.NewEncoder(w).Encode(user); err != nil {
+		http.Error(w, "Error encoding JSON response", http.StatusInternalServerError)
+	}
+}
+
+func (h *UserHandler) DeleteUserById(w http.ResponseWriter, r *http.Request) {
+	vars := mux.Vars(r)   // Obtener las variables de la ruta
+	idParam := vars["id"] // Obtener el ID del usuario
+
+	id, err := strconv.ParseUint(idParam, 10, 32) // Convertir el ID a uint
+	if err != nil {
+		http.Error(w, "Invalid user ID", http.StatusBadRequest)
+		return
+	}
+
+	// Buscar el usuario en la base de datos
+	user, err := h.queryService.GetUserById(uint(id))
+	if err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			http.Error(w, "User not found", http.StatusNotFound)
+			return
+		}
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+
+	// Eliminar el usuario (soft delete)
+	if err := h.commandService.DeleteUserById(user.ID); err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+
+	w.Header().Set("Content-Type", "application/json")
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(map[string]string{
+		"message": "User successfully deleted",
+	})
+}

+ 33 - 0
internal/models/user.go

@@ -0,0 +1,33 @@
+package models
+
+import (
+	"regexp"
+
+	"github.com/go-playground/validator/v10"
+	"gorm.io/gorm"
+)
+
+// User struct with validation tags
+type User struct {
+	gorm.Model
+	FirstName string `json:"first_name" validate:"required,min=2,max=40,uppercase"`
+	LastName  string `json:"last_name" validate:"required,min=2,max=40,uppercase"`
+	Sex       string `json:"sex" validate:"required,oneof=H M"`
+	BirthDate string `json:"birth_date" validate:"required,birthdate"` //dd-mm-yyyy
+}
+
+// Validate validates the User struct
+func (u *User) Validate() error {
+	validate := validator.New()
+	// Custom validation for BirthDate
+	validate.RegisterValidation("birthdate", func(fl validator.FieldLevel) bool {
+		re := regexp.MustCompile(`^(0[1-9]|[12][0-9]|3[01])-(0[1-9]|1[0-2])-\d{4}$`)
+		return re.MatchString(fl.Field().String())
+	})
+	// Custom validation for Uppercase
+	validate.RegisterValidation("uppercase", func(fl validator.FieldLevel) bool {
+		re := regexp.MustCompile(`^[A-Z]+$`) // Permite solo letras mayúsculas
+		return re.MatchString(fl.Field().String())
+	})
+	return validate.Struct(u)
+}

+ 13 - 0
internal/query/get_user_by_id_query.go

@@ -0,0 +1,13 @@
+package query
+
+// GetUserByIdQuery representa una consulta para obtener un usuario por su ID
+type GetUserByIdQuery struct {
+	ID uint `json:"id"` // Puedes incluir etiquetas JSON si necesitas serializar
+}
+
+// NewGetUserByIdQuery crea una nueva instancia de GetUserByIdQuery
+func NewGetUserByIdQuery(id uint) *GetUserByIdQuery {
+	return &GetUserByIdQuery{
+		ID: id,
+	}
+}

+ 7 - 0
internal/query/get_users_query.go

@@ -0,0 +1,7 @@
+package query
+
+type GetUsersQuery struct {}
+
+func NewGetUsersQuery() *GetUsersQuery {
+    return &GetUsersQuery{}
+}

+ 51 - 0
internal/repository/user_repository.go

@@ -0,0 +1,51 @@
+package repository
+
+import (
+	"log"
+
+	"api-dockerization/internal/models"
+
+	"gorm.io/gorm"
+)
+
+type UserRepository interface {
+	Create(user *models.User) error
+	GetAll() ([]models.User, error)
+	GetByID(id uint) (*models.User, error)
+	DeleteByID(id uint) error // Método que agregamos
+
+}
+
+type userRepository struct {
+	db *gorm.DB
+}
+
+func NewUserRepository(db *gorm.DB) UserRepository {
+	return &userRepository{db}
+}
+
+func (r *userRepository) Create(user *models.User) error {
+	log.Printf("Creating user: %+v\n", user) // Agrega esta línea para depuración
+	return r.db.Create(user).Error
+}
+
+func (r *userRepository) GetAll() ([]models.User, error) {
+	var users []models.User
+	err := r.db.Find(&users).Error
+	return users, err
+}
+
+// GetByID obtiene un usuario por su ID
+func (r *userRepository) GetByID(id uint) (*models.User, error) {
+	var user models.User
+	if err := r.db.First(&user, id).Error; err != nil {
+		return nil, err
+	}
+	return &user, nil
+}
+func (r *userRepository) DeleteByID(id uint) error {
+	if err := r.db.Delete(&models.User{}, id).Error; err != nil {
+		return err
+	}
+	return nil
+}

+ 30 - 0
internal/service/user_command_service.go

@@ -0,0 +1,30 @@
+package service
+
+import (
+	"api-dockerization/internal/command"
+	"api-dockerization/internal/models"
+	"api-dockerization/internal/repository"
+)
+
+type UserCommandService struct {
+	userRepository repository.UserRepository
+}
+
+func NewUserCommandService(repo repository.UserRepository) *UserCommandService {
+	return &UserCommandService{
+		userRepository: repo,
+	}
+}
+
+func (s *UserCommandService) CreateUser(cmd *command.CreateUserCommand) error {
+	user := &models.User{
+		FirstName: cmd.FirstName,
+		LastName:  cmd.LastName,
+		Sex:       cmd.Sex,
+		BirthDate: cmd.BirthDate,
+	}
+	return s.userRepository.Create(user)
+}
+func (s *UserCommandService) DeleteUserById(id uint) error {
+	return s.userRepository.DeleteByID(id)
+}

+ 24 - 0
internal/service/user_query_service.go

@@ -0,0 +1,24 @@
+package service
+
+import (
+	"api-dockerization/internal/models"
+	"api-dockerization/internal/repository"
+)
+
+type UserQueryService struct {
+	userRepository repository.UserRepository
+}
+
+func NewUserQueryService(repo repository.UserRepository) *UserQueryService {
+	return &UserQueryService{
+		userRepository: repo,
+	}
+}
+
+func (s *UserQueryService) GetUsers() ([]models.User, error) {
+	return s.userRepository.GetAll()
+}
+
+func (s *UserQueryService) GetUserById(id uint) (*models.User, error) {
+	return s.userRepository.GetByID(id)
+}

+ 15 - 0
routes/user_routes.go

@@ -0,0 +1,15 @@
+package routes
+
+import (
+	"api-dockerization/internal/handlers"
+
+	"github.com/gorilla/mux"
+)
+
+// SetupUserRoutes configura las rutas relacionadas con los usuarios
+func SetupUserRoutes(r *mux.Router, userHandler *handlers.UserHandler) {
+	r.HandleFunc("/api/v1/users", userHandler.CreateUser).Methods("POST")
+	r.HandleFunc("/api/v1/users", userHandler.GetUsers).Methods("GET")
+	r.HandleFunc("/api/v1/users/{id}", userHandler.GetUserById).Methods("GET")
+	r.HandleFunc("/api/v1/users/{id}", userHandler.DeleteUserById).Methods("DELETE")
+}