Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
POSTGRES_USER = "user"
POSTGRES_PASSWORD = "pass"
POSTGRES_HOST = "db"
POSTGRES_PORT = "5432"
POSTGRES_DB = "db"
API_PORT = "80"
19 changes: 11 additions & 8 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
# docker file for building Go application
FROM ubuntu:latest
FROM golang:alpine

# Install dependencies
RUN sudo apt install -y git go wget
WORKDIR /app

COPY . /app
COPY . .

WORKDIR /app
RUN go get github.com/lib/pq

RUN go get github.com/joho/godotenv

RUN go get github.com/rs/zerolog/log

# Build the application
RUN go build -o main .

CMD [ "main" ]
EXPOSE 80

CMD [ "./main" ]
29 changes: 0 additions & 29 deletions api.go

This file was deleted.

20 changes: 20 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
version: '3'

services:
db:
image: postgres:latest
env_file:
- .env
volumes:
- postgres_data:/var/lib/postgresql/data
api:
build:
context: .
dockerfile: Dockerfile
ports:
- "8091:80"
depends_on:
- db
volumes:
postgres_data:

2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module screening

go 1.21.3
go 1.21.3
12 changes: 12 additions & 0 deletions handler/create.handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package handler

import (
"database/sql"
)

// Raw query for inserting
func CreateUser(conn *sql.DB, name string, email string) error {
query := "INSERT INTO Users (name, email) VALUES ($1, $2)"
_, err := conn.Exec(query, name, email)
return err
}
22 changes: 22 additions & 0 deletions handler/update.handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package handler

import (
"database/sql"
)

// Raw query for updating with some conditional handlings
func UpdateUser(conn *sql.DB, name string, email string, id int) error {
var query string
var err error
if name == "" && email != "" {
query = "UPDATE Users SET email = $1 WHERE id = $2"
_, err = conn.Exec(query, email, id)
} else if name != "" && email == "" {
query = "UPDATE Users SET name = $1 WHERE id = $2"
_, err = conn.Exec(query, name, id)
} else {
query = "UPDATE Users SET name = $1, email = $2 WHERE id = $3"
_, err = conn.Exec(query, name, email, id)
}
return err
}
18 changes: 16 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
package main

import (
"fmt"
"net/http"
"os"
"screening/router"
"screening/utils"

"github.com/joho/godotenv"
)

func main() {
setupJsonApi()
http.ListenAndServe(":80", nil)
//Loading envs
godotenv.Load()
apiPort := os.Getenv("API_PORT")
apiPortFmt := fmt.Sprintf(":%s", apiPort)

// DB Connection and Route registering
conn := utils.CreateConnection()
router.RegisterRoute(conn)
defer conn.Close()
http.ListenAndServe(apiPortFmt, nil)
}
56 changes: 56 additions & 0 deletions router/create.router.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package router

import (
"database/sql"
"encoding/json"
"io/ioutil"
"net/http"
"screening/handler"
"screening/utils"
)

// Router to create a user, db connection object as param
func CreateRoute(conn *sql.DB) {
logger := utils.Logger()
var responseData utils.ResponseData
http.HandleFunc("/createUser", func(w http.ResponseWriter, r *http.Request) {
// route only for POST method
if r.Method == http.MethodPost {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Error reading request body", http.StatusBadRequest)
return
}
var user utils.CreateUserType
err = json.Unmarshal(body, &user)
if user.Name == "" {
responseData.Success = false
responseData.Message = "Name attribute missing"
} else if user.Email == "" {
responseData.Success = false
responseData.Message = "Email attribute missing"
} else {
// Calling the handler method
err = handler.CreateUser(conn, user.Name, user.Email)
if err != nil {
responseData.Success = false
responseData.Message = "User Create Error!"
} else {
responseData.Success = true
responseData.Message = "User Created!"
}
}
} else {
responseData.Success = false
responseData.Message = "Method not found!"
}
jsonData, jsonError := json.Marshal(responseData)
if jsonError != nil {
logger.Error().Msg("Error encoding JSON")
http.Error(w, "Error encoding JSON", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(jsonData)
})
}
11 changes: 11 additions & 0 deletions router/register.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package router

import (
"database/sql"
)

// Registering all available routes
func RegisterRoute(conn *sql.DB) {
CreateRoute(conn)
UpdateRouter(conn)
}
54 changes: 54 additions & 0 deletions router/update.router.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package router

import (
"database/sql"
"encoding/json"
"io/ioutil"
"net/http"
"screening/handler"
"screening/utils"
)

// Router to create a user, db connection object as param
func UpdateRouter(conn *sql.DB) {
logger := utils.Logger()
var responseData utils.ResponseData
http.HandleFunc("/updateUser", func(w http.ResponseWriter, r *http.Request) {
// route only for PATCH method
if r.Method == http.MethodPatch {
body, err := ioutil.ReadAll(r.Body)
logger.Error().Msg("Error reading request body")
if err != nil {
http.Error(w, "Error reading request body", http.StatusBadRequest)
return
}
var user utils.UpdateUserType
err = json.Unmarshal(body, &user)
if user.Id == 0 {
responseData.Success = false
responseData.Message = "id attribute missing"
} else {
// Calling the handler method
err = handler.UpdateUser(conn, user.Name, user.Email, user.Id)
if err != nil {
responseData.Success = false
responseData.Message = "User Updated Error!"
} else {
responseData.Success = true
responseData.Message = "User Updated!"
}
}
} else {
responseData.Success = false
responseData.Message = "Method not found!"
}
jsonData, jsonError := json.Marshal(responseData)
if jsonError != nil {
logger.Error().Msg("Error encoding JSON")
http.Error(w, "Error encoding JSON", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(jsonData)
})
}
13 changes: 0 additions & 13 deletions utils.go

This file was deleted.

49 changes: 49 additions & 0 deletions utils/connection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package utils

import (
"database/sql"
"fmt"
_ "github.com/lib/pq"
"os"
)

func CreateConnection() *sql.DB {
logger := Logger()
// Loading envs
user := os.Getenv("POSTGRES_USER")
password := os.Getenv("POSTGRES_PASSWORD")
dbName := os.Getenv("POSTGRES_DB")
port := os.Getenv("POSTGRES_PORT")
host := os.Getenv("POSTGRES_HOST")
connUrl := fmt.Sprintf(
"postgres://%s:%s@%s:%s/%s?sslmode=disable",
user, password, host, port, dbName,
)

// DB Connection
conn, err := sql.Open("postgres", connUrl)
if err != nil {
logger.Error().Msg("Error opening database connection: " + err.Error())
}
err = conn.Ping()
if err != nil {
logger.Error().Msg("Error pinging database: " + err.Error())
}
logger.Info().Msg("Connected to the PostgreSQL database successfully!")

// SQL query to create the "users" table
query := `
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(50)
)`

// Execute the query
_, err = conn.Exec(query)
if err != nil {
logger.Error().Msg("Error creating table: " + err.Error())
}

return conn
}
17 changes: 17 additions & 0 deletions utils/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package utils

import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"os"
)

func Logger() zerolog.Logger {
// logger file setup
file, err := os.OpenFile("file.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
log.Fatal().Err(err).Msg("Failed to open log file")
}
logger := zerolog.New(file).With().Timestamp().Logger()
return logger
}
19 changes: 19 additions & 0 deletions utils/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package utils

// All structs used in this project

type CreateUserType struct {
Name string `json:"name"`
Email string `json:"email"`
}

type UpdateUserType struct {
Id int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}

type ResponseData struct {
Success bool `json:"success"`
Message string `json:"message"`
}