Snippets for interview
Last active
July 13, 2022 07:51
-
-
Save bitroniq/ff6d6e48a2f8e646603ab5f6d705e9c8 to your computer and use it in GitHub Desktop.
log-shipping-api
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
MYSQL_HOST = localhost:3306 | |
MYSQL_DATABASE = kafka_test | |
MYSQL_USERNAME = root | |
MYSQL_PASSWORD = root | |
API_HOST = localhost | |
API_PORT = 8080 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"database/sql" | |
"fmt" | |
"log" | |
"net/http" | |
"os" | |
"strings" | |
_ "github.com/go-sql-driver/mysql" | |
"github.com/gorilla/mux" | |
"github.com/joho/godotenv" | |
kingpin "gopkg.in/alecthomas/kingpin.v2" | |
) | |
var ( | |
host = kingpin.Flag("host", "Host for this service").String() | |
port = kingpin.Flag("port", "Port for this service").String() | |
config = kingpin.Flag("config", "Path of config file").String() | |
) | |
const DEFAULT_HOST = "localhost" | |
const DEFAULT_PORT = "8080" | |
func main() { | |
kingpin.Parse() | |
r := mux.NewRouter() | |
// connect to db | |
var err error | |
if *config != "" { | |
err = godotenv.Load(*config) | |
} else { | |
err = godotenv.Load() | |
} | |
if err != nil { | |
log.Panic("Loading error while loading environment: ", err) | |
} | |
log.Println("Environment set up successfully!") | |
// set up host and port | |
hostP := *host | |
portP := *port | |
// Set host | |
if hostP == "" { | |
osEnvHost := os.Getenv("API_HOST") | |
if osEnvHost == "" { | |
hostP = DEFAULT_HOST | |
} else { | |
hostP = osEnvHost | |
} | |
} | |
// Set port | |
if portP == "" { | |
osEnvPort := os.Getenv("API_PORT") | |
if osEnvPort == "" { | |
portP = DEFAULT_PORT | |
} else { | |
portP = osEnvPort | |
} | |
} | |
var b strings.Builder | |
fmt.Fprintf(&b, "%s:%s@tcp(%s)/%s?charset=utf8", os.Getenv("MYSQL_USERNAME"), os.Getenv("MYSQL_PASSWORD"), os.Getenv("MYSQL_HOST"), os.Getenv("MYSQL_DATABASE")) | |
// try to connect db. | |
var db *sql.DB | |
db, err = sql.Open("mysql", b.String()) | |
if err != nil { | |
log.Panic("Failed to connected to DB: ", err) | |
} | |
err = db.Ping() | |
if err != nil { | |
db.Close() | |
log.Panic("Failed to connected to DB: ", err) | |
} | |
log.Println("Sucessfully connected to db.") | |
serverMapping := ServerMapping{DB: db} | |
// A route with a route variable: | |
r.HandleFunc("/server-mapping", serverMapping.CreateServerMapping).Methods("POST") | |
r.HandleFunc("/server-mapping", serverMapping.GetServerMapping).Methods("GET") | |
r.HandleFunc("/server-mapping/{id}", serverMapping.GetServerMapping).Methods("GET") | |
r.HandleFunc("/server-mapping/{id}", serverMapping.UpdateServerMapping).Methods("PUT") | |
r.HandleFunc("/server-mapping/{id}", serverMapping.DeleteServerMapping).Methods("DELETE") | |
server := fmt.Sprintf("%s:%s", hostP, portP) | |
log.Printf("Server is running on %s", server) | |
http.ListenAndServe(server, r) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"database/sql" | |
"encoding/json" | |
"log" | |
"net/http" | |
"github.com/gorilla/mux" | |
) | |
type ServerMapping struct { | |
DB *sql.DB | |
} | |
type ErrorResponse struct { | |
Code int `json:"code"` | |
Message string `json:"message"` | |
} | |
type GetServerMappingResponse struct { | |
ID int64 `json:"id"` | |
Host string `json:"host"` | |
Server string `json:"server"` | |
} | |
type CreateServerMappingRequest struct { | |
Host string `json:"host"` | |
Server string `json:"server"` | |
} | |
// CreateServerMapping create a new server mapping | |
func (serverMapping *ServerMapping) CreateServerMapping(w http.ResponseWriter, r *http.Request) { | |
log.Println("Create request is accepted.") | |
w.Header().Set("Content-Type", "application/json") | |
if r.Body == nil { | |
log.Printf("Status: %d Message: Must supply body.", http.StatusBadRequest) | |
w.WriteHeader(http.StatusBadRequest) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusBadRequest, Message: "Must supply body."}) | |
return | |
} | |
defer r.Body.Close() | |
params := CreateServerMappingRequest{} | |
if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { | |
log.Printf("Status: %d Failed to decode params: %s", http.StatusBadRequest, err) | |
w.WriteHeader(http.StatusBadRequest) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusBadRequest, Message: "Unable to decode body."}) | |
return | |
} | |
if params.Host == "" || params.Server == "" { | |
log.Printf("Status: %d Must supply host and server in the body", http.StatusBadRequest) | |
w.WriteHeader(http.StatusBadRequest) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusBadRequest, Message: "Must supply host and server."}) | |
return | |
} | |
const insertSQL = ` | |
INSERT INTO sys_servers (host, server) VALUES (?, ?) | |
` | |
stmtIns, err := serverMapping.DB.Prepare(insertSQL) | |
if err != nil { | |
log.Printf("Status: %d DB Error: %s", http.StatusForbidden, err) | |
w.WriteHeader(http.StatusForbidden) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusForbidden, Message: "DB Error."}) | |
return | |
} | |
defer stmtIns.Close() // Close | |
_, err = stmtIns.Exec(params.Host, params.Server) | |
if err != nil { | |
log.Printf("Status: %d DB Error: %s", http.StatusForbidden, err) | |
w.WriteHeader(http.StatusForbidden) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusForbidden, Message: "DB Error."}) | |
return | |
} | |
const getLastInsertSQL = ` | |
SELECT * FROM sys_servers WHERE id= LAST_INSERT_ID() | |
` | |
response := GetServerMappingResponse{} | |
if err := serverMapping.DB.QueryRow(getLastInsertSQL).Scan(&response.ID, &response.Host, &response.Server); err != nil { | |
log.Printf("Status: %d DB Error: %s", http.StatusForbidden, err) | |
w.WriteHeader(http.StatusForbidden) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusForbidden, Message: "DB Error."}) | |
return | |
} | |
log.Println("Successfully created mapping") | |
w.WriteHeader(http.StatusCreated) | |
json.NewEncoder(w).Encode(response) | |
} | |
// GetServerMapping get server mapping based on id and host | |
func (serverMapping *ServerMapping) GetServerMapping(w http.ResponseWriter, r *http.Request) { | |
log.Println("Get request is accepted.") | |
mappingID := mux.Vars(r)["id"] | |
searchHost := r.FormValue("host") | |
defer r.Body.Close() | |
w.Header().Set("Content-Type", "application/json") | |
if mappingID != "" { | |
// Query with id | |
log.Println("Searching mappings using id:", mappingID) | |
selectQuery := `SELECT id, host, server FROM sys_servers WHERE id=?;` | |
var mapping GetServerMappingResponse | |
if err := serverMapping.DB.QueryRow(selectQuery, mappingID).Scan(&mapping.ID, &mapping.Host, &mapping.Server); err != nil { | |
if err == sql.ErrNoRows { | |
log.Printf("Status: %d %s is invalid id.", http.StatusBadRequest, mappingID) | |
w.WriteHeader(http.StatusBadRequest) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusBadRequest, Message: "Invalid id is provided."}) | |
return | |
} | |
log.Printf("Status: %d DB Error: %s", http.StatusForbidden, err) | |
w.WriteHeader(http.StatusForbidden) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusForbidden, Message: "DB Error."}) | |
return | |
} | |
json.NewEncoder(w).Encode(mapping) | |
} else if searchHost != "" { | |
// Query with host | |
log.Println("Searching mapping using host:", searchHost) | |
selectQuery := `SELECT id, host, server FROM sys_servers WHERE host=?;` | |
rows, err := serverMapping.DB.Query(selectQuery, searchHost) | |
if err != nil { | |
log.Printf("Status: %d DB Error: %s", http.StatusForbidden, err) | |
w.WriteHeader(http.StatusForbidden) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusForbidden, Message: "DB Error."}) | |
return | |
} | |
defer rows.Close() | |
mappings := []GetServerMappingResponse{} | |
for rows.Next() { | |
mapping := GetServerMappingResponse{} | |
if err := rows.Scan(&mapping.ID, &mapping.Host, &mapping.Server); err != nil { | |
log.Printf("Status: %d DB Error: %s", http.StatusForbidden, err) | |
w.WriteHeader(http.StatusForbidden) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusForbidden, Message: "DB Error."}) | |
return | |
} | |
mappings = append(mappings, mapping) | |
} | |
json.NewEncoder(w).Encode(mappings) | |
} else { | |
log.Println("Search all mappings") | |
selectQuery := `SELECT id, host, server FROM sys_servers;` | |
rows, err := serverMapping.DB.Query(selectQuery) | |
if err != nil { | |
log.Printf("Status: %d DB Error: %s", http.StatusForbidden, err) | |
w.WriteHeader(http.StatusForbidden) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusForbidden, Message: "DB Error."}) | |
return | |
} | |
defer rows.Close() | |
mappings := []GetServerMappingResponse{} | |
for rows.Next() { | |
mapping := GetServerMappingResponse{} | |
if err := rows.Scan(&mapping.ID, &mapping.Host, &mapping.Server); err != nil { | |
log.Printf("Status: %d DB Error: %s", http.StatusForbidden, err) | |
w.WriteHeader(http.StatusForbidden) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusForbidden, Message: "DB Error."}) | |
return | |
} | |
mappings = append(mappings, mapping) | |
} | |
json.NewEncoder(w).Encode(mappings) | |
} | |
} | |
// UpdateServerMapping updates server mapping | |
func (serverMapping *ServerMapping) UpdateServerMapping(w http.ResponseWriter, r *http.Request) { | |
log.Println("Get request is accepted.") | |
w.Header().Set("Content-Type", "application/json") | |
mappingID := mux.Vars(r)["id"] | |
defer r.Body.Close() | |
params := CreateServerMappingRequest{} | |
if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { | |
log.Printf("Status: %d Failed to decode params: %s", http.StatusBadRequest, err) | |
w.WriteHeader(http.StatusBadRequest) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusBadRequest, Message: "Unable to decode body."}) | |
return | |
} | |
if params.Host == "" || params.Server == "" { | |
log.Printf("Status: %d Must supply host and server in the body", http.StatusBadRequest) | |
w.WriteHeader(http.StatusBadRequest) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusBadRequest, Message: "Must supply host and server."}) | |
return | |
} | |
log.Println("Searching mappings using id:", mappingID) | |
selectQuery := `SELECT id, host, server FROM sys_servers WHERE id=?;` | |
var mapping GetServerMappingResponse | |
if err := serverMapping.DB.QueryRow(selectQuery, mappingID).Scan(&mapping.ID, &mapping.Host, &mapping.Server); err != nil { | |
if err == sql.ErrNoRows { | |
log.Printf("Status: %d %s is invalid id.", http.StatusBadRequest, mappingID) | |
w.WriteHeader(http.StatusBadRequest) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusBadRequest, Message: "Invalid id is provided."}) | |
return | |
} | |
log.Printf("Status: %d DB Error: %s", http.StatusForbidden, err) | |
w.WriteHeader(http.StatusForbidden) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusForbidden, Message: "DB Error."}) | |
return | |
} | |
log.Println("Updating mappings using id:", mappingID) | |
updateQuery := `UPDATE sys_servers SET host = ?, server = ? WHERE id=?;` | |
stmtIns, err := serverMapping.DB.Prepare(updateQuery) | |
if err != nil { | |
log.Printf("Status: %d DB Error: %s", http.StatusForbidden, err) | |
w.WriteHeader(http.StatusForbidden) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusForbidden, Message: "DB Error."}) | |
return | |
} | |
defer stmtIns.Close() // Close | |
_, err = stmtIns.Exec(params.Host, params.Server, mappingID) | |
if err != nil { | |
log.Printf("Status: %d DB Error: %s", http.StatusForbidden, err) | |
w.WriteHeader(http.StatusForbidden) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusForbidden, Message: "DB Error."}) | |
return | |
} | |
log.Println("Successfully updated mapping") | |
return | |
} | |
// DeleteServerMapping deletes server mapping | |
func (serverMapping *ServerMapping) DeleteServerMapping(w http.ResponseWriter, r *http.Request) { | |
log.Println("Get request is accepted.") | |
mappingID := mux.Vars(r)["id"] | |
defer r.Body.Close() | |
w.Header().Set("Content-Type", "application/json") | |
log.Println("Searching mappings using id:", mappingID) | |
selectQuery := `SELECT id, host, server FROM sys_servers WHERE id=?;` | |
var mapping GetServerMappingResponse | |
if err := serverMapping.DB.QueryRow(selectQuery, mappingID).Scan(&mapping.ID, &mapping.Host, &mapping.Server); err != nil { | |
if err == sql.ErrNoRows { | |
log.Printf("Status: %d %s is invalid id.", http.StatusBadRequest, mappingID) | |
w.WriteHeader(http.StatusBadRequest) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusBadRequest, Message: "Invalid id is provided."}) | |
return | |
} | |
log.Printf("Status: %d DB Error: %s", http.StatusForbidden, err) | |
w.WriteHeader(http.StatusForbidden) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusForbidden, Message: "DB Error."}) | |
return | |
} | |
log.Println("Deleting mappings using id:", mappingID) | |
deleteQuery := `DELETE from sys_servers WHERE id=?;` | |
stmtIns, err := serverMapping.DB.Prepare(deleteQuery) | |
if err != nil { | |
log.Printf("Status: %d DB Error: %s", http.StatusForbidden, err) | |
w.WriteHeader(http.StatusForbidden) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusForbidden, Message: "DB Error."}) | |
return | |
} | |
defer stmtIns.Close() // Close | |
_, err = stmtIns.Exec(mappingID) | |
if err != nil { | |
log.Printf("Status: %d DB Error: %s", http.StatusForbidden, err) | |
w.WriteHeader(http.StatusForbidden) | |
json.NewEncoder(w).Encode(ErrorResponse{Code: http.StatusForbidden, Message: "DB Error."}) | |
return | |
} | |
log.Println("Successfully deleted mapping") | |
return | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment