diff --git a/.air.conf b/.air.conf new file mode 100644 index 0000000..ee85e6e --- /dev/null +++ b/.air.conf @@ -0,0 +1,41 @@ +# Working directory +# . or absolute path, please note that the directories following must be under root. +root = "." +tmp_dir = "tmp" + +[build] +# Just plain old shell command. You could use `make` as well. +cmd = "make build" +# Binary file yields from `cmd`. +bin = "build" +# Customize binary. +full_bin = "./build" +# Watch these filename extensions. +include_ext = ["go", "tpl", "tmpl", "html"] +# Ignore these filename extensions or directories. +exclude_dir = ["assets", "tmp", "vendor", "frontend/node_modules"] +# Watch these directories if you specified. +include_dir = [] +# Exclude files. +exclude_file = [] +# It's not necessary to trigger build each time file changes if it's too frequent. +delay = 1000 # ms +# Stop to run old binary when build errors occur. +stop_on_error = true +# This log file places in your tmp_dir. +log = "air_errors.log" + +[log] +# Show log time +time = false + +[color] +# Customize each part's color. If no color found, use the raw app log. +main = "magenta" +watcher = "cyan" +build = "yellow" +runner = "green" + +[misc] +# Delete tmp directory on exit +clean_on_exit = true \ No newline at end of file diff --git a/README.md b/README.md index d17bd05..b21ad5b 100644 --- a/README.md +++ b/README.md @@ -2,20 +2,34 @@ [![Go](https://img.shields.io/badge/go-00ADD8.svg?style=for-the-badge&logo=go&logoColor=white)](https://go.dev/) -Order management microservice. +Mission Control microservice. ## Development -To get started, clone this repository and follow theese steps. +To get started, clone this repository and follow these steps to run the Go application in your local environment. -Run Docker Containers: +Start all of the Docker containers in the background, you may start in "detached" mode: ```bash docker-compose up -d ``` -Running Database Migrations (use arg action): +The application is executing within a Docker container and is isolated from your local computer. To run various commands against your application use: + +```bash +docker-compose exec app {CMD} +``` + +## Database Migrations + +Run all of your outstanding migrations: ```bash make migrate action=up ``` + +Roll back the latest migration operation, you may use the rollback Artisan command. This command rolls back the last "batch" of migrations, which may include multiple migration files: + +```bash +make migrate action=down +``` diff --git a/docker-compose.yml b/docker-compose.yml index 6fb0552..8fffdf8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,14 @@ -version: '3' - services: + app: + image: cosmtrek/air + working_dir: /app + ports: + - 80:3000 + env_file: ".env" + volumes: + - ./:/app + depends_on: + - mysql mysql: image: mariadb environment: diff --git a/domain/mission/endpoint.go b/domain/mission/endpoint.go index 6d0ae6e..16b0b4a 100644 --- a/domain/mission/endpoint.go +++ b/domain/mission/endpoint.go @@ -11,8 +11,9 @@ func Routes(router *http.ServeMux, db *sql.DB) { basePath := os.Getenv("BASE_PATH") - router.HandleFunc("POST "+basePath+"/missions", handler.Create) - router.HandleFunc("GET "+basePath+"/missions/{id}", handler.FindByID) - router.HandleFunc("PUT "+basePath+"/missions/{id}", handler.UpdateByID) - router.HandleFunc("DELETE "+basePath+"/missions/{id}", handler.DeleteByID) + router.HandleFunc("GET "+basePath+"/missions", handler.Index) + router.HandleFunc("POST "+basePath+"/missions", handler.Store) + router.HandleFunc("GET "+basePath+"/missions/{id}", handler.Show) + router.HandleFunc("PUT "+basePath+"/missions/{id}", handler.Update) + router.HandleFunc("DELETE "+basePath+"/missions/{id}", handler.Destroy) } diff --git a/domain/mission/handler.go b/domain/mission/handler.go index 4d27973..21e245c 100644 --- a/domain/mission/handler.go +++ b/domain/mission/handler.go @@ -20,7 +20,23 @@ func NewHandler(db *sql.DB) *Handler { } } -func (h *Handler) Create(w http.ResponseWriter, r *http.Request) { +func (h *Handler) Index(w http.ResponseWriter, r *http.Request) { + mission, err := h.repo.GetAll() + if err != nil { + http.Error(w, fmt.Sprintf("Error finding mission: %v", err), http.StatusInternalServerError) + return + } + + if mission == nil { + http.NotFound(w, r) + return + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(mission) +} + +func (h *Handler) Store(w http.ResponseWriter, r *http.Request) { var payload struct { Name string `json:"name"` Description string `json:"description"` @@ -45,7 +61,7 @@ func (h *Handler) Create(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(mission) } -func (h *Handler) FindByID(w http.ResponseWriter, r *http.Request) { +func (h *Handler) Show(w http.ResponseWriter, r *http.Request) { idStr := r.PathValue("id") id, err := strconv.Atoi(idStr) if err != nil { @@ -68,7 +84,7 @@ func (h *Handler) FindByID(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(mission) } -func (h *Handler) UpdateByID(w http.ResponseWriter, r *http.Request) { +func (h *Handler) Update(w http.ResponseWriter, r *http.Request) { idStr := r.PathValue("id") id, err := strconv.Atoi(idStr) if err != nil { @@ -102,7 +118,7 @@ func (h *Handler) UpdateByID(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Mission updated successfully") } -func (h *Handler) DeleteByID(w http.ResponseWriter, r *http.Request) { +func (h *Handler) Destroy(w http.ResponseWriter, r *http.Request) { idStr := r.PathValue("id") id, err := strconv.Atoi(idStr) if err != nil { diff --git a/domain/mission/mysql.go b/domain/mission/mysql.go index 11ee979..c3b762d 100644 --- a/domain/mission/mysql.go +++ b/domain/mission/mysql.go @@ -15,6 +15,34 @@ func NewMySQLMissionRepository(db *sql.DB) *MySQLMissionRepository { return &MySQLMissionRepository{db: db} } +func (r *MySQLMissionRepository) GetAll() (*[]domain.Mission, error) { + query := "SELECT id, name, description, created_at, updated_at FROM missions" + rows, err := r.db.Query(query) + if err != nil { + return nil, err + } + defer rows.Close() + + var missions []domain.Mission + + for rows.Next() { + var mission domain.Mission + var createdAt, updatedAt []uint8 + + err := rows.Scan(&mission.ID, &mission.Name, &mission.Description, &createdAt, &updatedAt) + if err != nil { + return nil, fmt.Errorf("error scanning mission: %w", err) + } + + missions = append(missions, mission) + } + if err = rows.Err(); err != nil { + return &missions, err + } + + return &missions, nil +} + func (r *MySQLMissionRepository) Create(mission *domain.Mission) error { query := "INSERT INTO missions (name, description) VALUES (?, ?)" result, err := r.db.Exec(query, mission.Name, mission.Description) diff --git a/domain/mission/repository.go b/domain/mission/repository.go index 5622eea..1233aaa 100644 --- a/domain/mission/repository.go +++ b/domain/mission/repository.go @@ -4,6 +4,7 @@ import "github.com/blazeisclone/spaceops-mission-ctrl/domain" type MissionRepository interface { Create(mission *domain.Mission) error + GetAll() (*[]domain.Mission, error) FindByID(id int) (*domain.Mission, error) UpdateByID(id int, mission *domain.Mission) error DeleteByID(id int) error