diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..fb54d63 Binary files /dev/null and b/.DS_Store differ diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..28c7770 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/screening.iml b/.idea/screening.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/screening.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index d1438c5..2b838a2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,13 @@ # docker file for building Go application -FROM ubuntu:latest - -# Install dependencies -RUN sudo apt install -y git go wget - -COPY . /app - +FROM golang:1.20 AS builder WORKDIR /app +COPY . . +RUN CGO_ENABLED=0 GOOS=linux go build -o main . -# Build the application -RUN go build -o main . -CMD [ "main" ] \ No newline at end of file +FROM alpine:3.9 as base +RUN apk --no-cache add ca-certificates +RUN apk --no-cache add tzdata +WORKDIR /app +COPY --from=builder /app/main . +CMD [ "./main" ] \ No newline at end of file diff --git a/api.go b/api.go index cbef2ef..7007520 100644 --- a/api.go +++ b/api.go @@ -1,29 +1,52 @@ package main import ( - "fmt" + "encoding/json" + "github.com/go-chi/chi" "net/http" ) -func setupJsonApi() { - http.HandleFunc("/createUser", func(w http.ResponseWriter, r *http.Request) { - // create mysql connection - conn := createConnection() - name := r.FormValue("name") - email := r.FormValue("email") - query := "INSERT INTO users (name, email) VALUES (" + name + ", " + email + ")" - result, err := conn.Exec(query) - fmt.Println("result ", result, " err ", err.Error()) - w.Write([]byte("Created user successfully!")) - }) - http.HandleFunc("/updateUser", func(w http.ResponseWriter, r *http.Request) { - // create mysql connection - conn := createConnection() - name := r.FormValue("name") - email := r.FormValue("email") - query := "Update users set name=" + name + ", email=" + email + " where id=" + r.FormValue("id") - result, err := conn.Exec(query) - fmt.Println("result ", result, " err ", err.Error()) - w.Write([]byte("User updated successfully!")) - }) +func (s *Server) setupRoutes() { + s.router.Post("/createUser", s.createUserHandler) + s.router.Put("/updateUser/{id}", s.updateUserHandler) +} + +func (s *Server) createUserHandler(w http.ResponseWriter, r *http.Request) { + conn := s.getDBConnection() + defer conn.Close() + + var user User + if err := json.NewDecoder(r.Body).Decode(&user); err != nil { + http.Error(w, "Bad Request: Invalid JSON", http.StatusBadRequest) + return + } + + query := `INSERT INTO users (name, email) VALUES ($1, $2)` + _, err := conn.Exec(query, user.Name, user.Email) + if err != nil { + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + + w.Write([]byte("Created user successfully!")) +} + +func (s *Server) updateUserHandler(w http.ResponseWriter, r *http.Request) { + conn := s.getDBConnection() + defer conn.Close() + + var user User + if err := json.NewDecoder(r.Body).Decode(&user); err != nil { + http.Error(w, "Bad Request", http.StatusBadRequest) + return + } + + query := `UPDATE users SET name=$1, email=$2 WHERE id=$3` + _, err := conn.Exec(query, user.Name, user.Email, chi.URLParam(r, "id")) + if err != nil { + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + + w.Write([]byte("User updated successfully!")) } diff --git a/go.mod b/go.mod index 541428f..b456bf7 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,8 @@ module screening -go 1.21.3 +go 1.20 + +require ( + github.com/go-chi/chi v1.5.5 + github.com/go-sql-driver/mysql v1.7.1 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..bf728cc --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/go-chi/chi v1.5.5 h1:vOB/HbEMt9QqBqErz07QehcOKHaWFtuj87tTDVz2qXE= +github.com/go-chi/chi v1.5.5/go.mod h1:C9JqLr3tIYjDOZpzn+BCuxY8z8vmca43EeMgyZt7irw= +github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= +github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= diff --git a/main.go b/main.go index 18805dd..cb59149 100644 --- a/main.go +++ b/main.go @@ -1,10 +1,53 @@ package main import ( + "database/sql" + "github.com/go-chi/chi" + "github.com/go-chi/chi/middleware" + _ "github.com/go-sql-driver/mysql" + "log" "net/http" + "sync" + "time" ) +type Server struct { + router *chi.Mux + db *sql.DB + mu sync.Mutex +} + +func NewServer() *Server { + return &Server{ + router: chi.NewRouter(), + } +} + +func (s *Server) Init() { + s.router.Use(middleware.Logger) + s.router.Use(middleware.Recoverer) + + s.setupRoutes() + s.initDBConnection() +} + +func (s *Server) Start(port string) error { + server := &http.Server{ + Addr: port, + Handler: s.router, + ReadTimeout: 5 * time.Second, + WriteTimeout: 10 * time.Second, + } + + log.Printf("Server started on port %s", port) + return server.ListenAndServe() +} + func main() { - setupJsonApi() - http.ListenAndServe(":80", nil) + server := NewServer() + server.Init() + + if err := server.Start(":8080"); err != nil { + log.Fatalf("Error starting server: %v", err) + } } diff --git a/model.go b/model.go new file mode 100644 index 0000000..cbdc729 --- /dev/null +++ b/model.go @@ -0,0 +1,7 @@ +package main + +type User struct { + ID int `json:"id,omitempty"` + Name string `json:"name"` + Email string `json:"email"` +} diff --git a/utils.go b/utils.go index e65cd87..7dd27ed 100644 --- a/utils.go +++ b/utils.go @@ -3,11 +3,28 @@ package main import ( "database/sql" "fmt" + "log" + "os" ) -// createConnection creates a connection to mysql database -func createConnection() *sql.DB { - db, err := sql.Open("mysql", "root:password@tcp(127.0.0.1:3306)/test") - fmt.Println("sql open " + err.Error()) - return db +func (s *Server) getDBConnection() *sql.DB { + s.mu.Lock() + defer s.mu.Unlock() + + return s.db +} + +func (s *Server) initDBConnection() { + dbHost := os.Getenv("DB_HOST") + dbPort := os.Getenv("DB_PORT") + dbUser := os.Getenv("DB_USER") + dbPassword := os.Getenv("DB_PASSWORD") + dbName := os.Getenv("DB_NAME") + + dbSource := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", dbUser, dbPassword, dbHost, dbPort, dbName) + conn, err := sql.Open("mysql", dbSource) + if err != nil { + log.Fatalf("Failed to connect to the database: %v", err) + } + s.db = conn }