diff --git a/.env b/.env index 96d9037..70c1ff9 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ DB_CONNECTION_STRING=postgres://isl:development@localhost:5432/isl -HTTP_PORT=3000 +HTTP_PORT=3001 diff --git a/Controllers/PowerItemController.go b/Controllers/PowerItemController.go index 7551830..c220682 100644 --- a/Controllers/PowerItemController.go +++ b/Controllers/PowerItemController.go @@ -6,42 +6,24 @@ import ( "net/http" "strconv" + "forgejo.merr.is/annika/isl-api/Entities" "forgejo.merr.is/annika/isl-api/Services" - "forgejo.merr.is/annika/isl-api/Types" - "github.com/julienschmidt/httprouter" + "github.com/go-chi/chi/v5" ) -// TODO: Figure out a better place to put this. -func MiddleCORS(next httprouter.Handle) httprouter.Handle { - return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - w.Header().Set("Access-Control-Allow-Origin", "*") - next(w, r, ps) - } -} - type PowerItemController struct { powerItemService *Services.PowerItemService } -func NewPowerItemController(router *httprouter.Router, powerItemService *Services.PowerItemService) *PowerItemController { +func NewPowerItemController(powerItemService *Services.PowerItemService) *PowerItemController { controller := &PowerItemController{ powerItemService: powerItemService, } - controller.setPowerItemEndpoints(router, "/powerItem") return controller } -func (p *PowerItemController) setPowerItemEndpoints(router *httprouter.Router, prefix string) { - router.GET(fmt.Sprintf("%v", prefix), MiddleCORS(p.getAll)) - router.GET(fmt.Sprintf("%v/asMap", prefix), MiddleCORS(p.getAllAsMap)) - router.GET(fmt.Sprintf("%v/byType/:type", prefix), MiddleCORS(p.getAllByType)) - router.GET(fmt.Sprintf("%v/byType/:type/asMap", prefix), MiddleCORS(p.getAllByTypeAsMap)) - router.POST(fmt.Sprintf("%v", prefix), MiddleCORS(p.add)) - router.POST(fmt.Sprintf("%v/multiple", prefix), MiddleCORS(p.addMultiple)) -} - -func (p *PowerItemController) add(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - var newItem Types.PowerItem +func (p *PowerItemController) Add(w http.ResponseWriter, r *http.Request) { + var newItem Entities.PowerItem err := json.NewDecoder(r.Body).Decode(&newItem) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) @@ -64,9 +46,9 @@ func (p *PowerItemController) add(w http.ResponseWriter, r *http.Request, ps htt fmt.Fprint(w, string(returnValue)) } -func (p *PowerItemController) addMultiple(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (p *PowerItemController) AddMultiple(w http.ResponseWriter, r *http.Request) { var itemType int32 = 3 - var newItems map[string]Types.PowerItem + var newItems map[string]Entities.PowerItem err := json.NewDecoder(r.Body).Decode(&newItems) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) @@ -92,7 +74,7 @@ func (p *PowerItemController) addMultiple(w http.ResponseWriter, r *http.Request fmt.Fprint(w, string(returnValue)) } -func (p *PowerItemController) getAll(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (p *PowerItemController) GetAll(w http.ResponseWriter, r *http.Request) { result, err := p.powerItemService.GetAll() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -109,14 +91,14 @@ func (p *PowerItemController) getAll(w http.ResponseWriter, r *http.Request, ps fmt.Fprint(w, string(data)) } -func (p *PowerItemController) getAllAsMap(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (p *PowerItemController) GetAllAsMap(w http.ResponseWriter, r *http.Request) { items, err := p.powerItemService.GetAll() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } - resultMap := make(map[string]Types.PowerItem) + resultMap := make(map[string]Entities.PowerItem) for _, curItem := range items { uuid := fmt.Sprintf("%x-%x-%x-%x-%x", curItem.ID.Bytes[0:4], curItem.ID.Bytes[4:6], curItem.ID.Bytes[6:8], curItem.ID.Bytes[8:10], curItem.ID.Bytes[10:16]) resultMap[uuid] = curItem @@ -132,8 +114,8 @@ func (p *PowerItemController) getAllAsMap(w http.ResponseWriter, r *http.Request fmt.Fprint(w, string(data)) } -func (p *PowerItemController) getAllByType(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - typeCode, err := strconv.Atoi(ps.ByName("type")) +func (p *PowerItemController) GetAllByType(w http.ResponseWriter, r *http.Request) { + typeCode, err := strconv.Atoi(chi.URLParam(r, "type")) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return @@ -155,8 +137,8 @@ func (p *PowerItemController) getAllByType(w http.ResponseWriter, r *http.Reques fmt.Fprint(w, string(data)) } -func (p *PowerItemController) getAllByTypeAsMap(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - typeCode, err := strconv.Atoi(ps.ByName("type")) +func (p *PowerItemController) GetAllByTypeAsMap(w http.ResponseWriter, r *http.Request) { + typeCode, err := strconv.Atoi(chi.URLParam(r, "type")) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return @@ -168,7 +150,7 @@ func (p *PowerItemController) getAllByTypeAsMap(w http.ResponseWriter, r *http.R return } - resultMap := make(map[string]Types.PowerItem) + resultMap := make(map[string]Entities.PowerItem) for _, curItem := range items { uuid := fmt.Sprintf("%x-%x-%x-%x-%x", curItem.ID.Bytes[0:4], curItem.ID.Bytes[4:6], curItem.ID.Bytes[6:8], curItem.ID.Bytes[8:10], curItem.ID.Bytes[10:16]) resultMap[uuid] = curItem diff --git a/Types/PowerItem.go b/Entities/PowerItem.go similarity index 99% rename from Types/PowerItem.go rename to Entities/PowerItem.go index d15123a..2e9faf7 100644 --- a/Types/PowerItem.go +++ b/Entities/PowerItem.go @@ -1,4 +1,4 @@ -package Types +package Entities import ( "forgejo.merr.is/annika/isl-api/sql/powerItem" diff --git a/Routes/PowerItemRoutes.go b/Routes/PowerItemRoutes.go new file mode 100644 index 0000000..a6c0457 --- /dev/null +++ b/Routes/PowerItemRoutes.go @@ -0,0 +1,19 @@ +package routes + +import ( + "forgejo.merr.is/annika/isl-api/Controllers" + "github.com/go-chi/chi/v5" +) + +func SetupPowerItemRoutes(c Controllers.PowerItemController) *chi.Mux { + r := chi.NewRouter() + + r.Get("/", c.GetAll) + r.Get("/asMap", c.GetAllAsMap) + r.Get("/byType/{type:[1-3]}", c.GetAllByType) + r.Get("/byType/{type:[1-3]}/asMap", c.GetAllByTypeAsMap) + r.Post("/", c.Add) + r.Post("/multiple", c.AddMultiple) + + return r +} diff --git a/Services/PowerItemService.go b/Services/PowerItemService.go index 0e3d17f..36deedb 100644 --- a/Services/PowerItemService.go +++ b/Services/PowerItemService.go @@ -3,7 +3,7 @@ package Services import ( "context" - "forgejo.merr.is/annika/isl-api/Types" + "forgejo.merr.is/annika/isl-api/Entities" "forgejo.merr.is/annika/isl-api/sql/powerItem" "github.com/jackc/pgtype" ) @@ -20,31 +20,31 @@ func NewPowerItemService(querier *powerItem.DBQuerier) *PowerItemService { } } -func (p *PowerItemService) GetAll() ([]Types.PowerItem, error) { +func (p *PowerItemService) GetAll() ([]Entities.PowerItem, error) { rows, err := p.querier.GetAllItems(p.context) if err != nil { - return []Types.PowerItem{}, err + return []Entities.PowerItem{}, err } - var powerItems []Types.PowerItem + var powerItems []Entities.PowerItem for _, sqlItem := range rows { - powerItems = append(powerItems, Types.FromGetAllItemsRow(sqlItem)) + powerItems = append(powerItems, Entities.FromGetAllItemsRow(sqlItem)) } return powerItems, nil } -func (p *PowerItemService) GetAllByType(itemType int) ([]Types.PowerItem, error) { +func (p *PowerItemService) GetAllByType(itemType int) ([]Entities.PowerItem, error) { rows, err := p.querier.GetAllByType(p.context, int32(itemType)) if err != nil { - return []Types.PowerItem{}, err + return []Entities.PowerItem{}, err } - var powerItems []Types.PowerItem + var powerItems []Entities.PowerItem for _, sqlItem := range rows { - powerItems = append(powerItems, Types.FromGetAllItemsByTypeRow(sqlItem)) + powerItems = append(powerItems, Entities.FromGetAllItemsByTypeRow(sqlItem)) } return powerItems, nil } -func (p *PowerItemService) Add(newItem Types.PowerItem) (Types.PowerItem, error) { +func (p *PowerItemService) Add(newItem Entities.PowerItem) (Entities.PowerItem, error) { sqlItem := powerItem.AddNewItemWithIDParams{ ID: newItem.ID, ItemType: newItem.ItemType, @@ -59,14 +59,14 @@ func (p *PowerItemService) Add(newItem Types.PowerItem) (Types.PowerItem, error) } row, err := p.querier.AddNewItemWithID(p.context, powerItem.AddNewItemWithIDParams(sqlItem)) if err != nil { - return Types.PowerItem{}, err + return Entities.PowerItem{}, err } - return Types.FromAddNewItemWithIDParams(row), nil + return Entities.FromAddNewItemWithIDParams(row), nil } -func (p *PowerItemService) AddMultipile(newItems map[string]Types.PowerItem, itemType int32) ([]Types.PowerItem, []error) { +func (p *PowerItemService) AddMultipile(newItems map[string]Entities.PowerItem, itemType int32) ([]Entities.PowerItem, []error) { var errors []error - var addedItems []Types.PowerItem + var addedItems []Entities.PowerItem for key, value := range newItems { id := pgtype.UUID{} id.Set(key) @@ -87,7 +87,7 @@ func (p *PowerItemService) AddMultipile(newItems map[string]Types.PowerItem, ite errors = append(errors, err) continue } - addedItems = append(addedItems, Types.FromAddNewItemWithIDParams(row)) + addedItems = append(addedItems, Entities.FromAddNewItemWithIDParams(row)) } return addedItems, errors } diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index abc8cab..5e81b59 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -9,7 +9,7 @@ services: - ISL_API_DB_CONNECTION_STRING=postgres://isl:development@db:5432/isl - ISL_API_HTTP_PORT=3000 ports: - - 3080:3000 + - 3000:3000 db: image: postgres restart: always @@ -26,4 +26,4 @@ services: image: adminer restart: always ports: - - 8080:8080 + - 8081:8080 diff --git a/go.mod b/go.mod index bc26edc..8b7afe6 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,8 @@ require ( require ( github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/go-chi/chi/v5 v5.0.11 // indirect + github.com/go-chi/cors v1.2.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgio v1.0.0 // indirect @@ -30,10 +32,11 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.18.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/zitadel/zitadel-go/v3 v3.0.0-next.2 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/crypto v0.16.0 // indirect - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 // indirect golang.org/x/sys v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 0a68bee..90b9ae9 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,10 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/go-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA= +github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= +github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -147,6 +151,8 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +github.com/zitadel/zitadel-go/v3 v3.0.0-next.2 h1:w0lnLvijwQwkrUEA74loenNR9udRAaq6rccjlMSA+4U= +github.com/zitadel/zitadel-go/v3 v3.0.0-next.2/go.mod h1:SY9IZuDw/766mwEobCX7JNwXawIQxVseo679JG1U0c0= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -178,6 +184,8 @@ golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 h1:+iq7lrkxmFNBM7xx+Rae2W6uyPfhPeDWD+n+JgppptE= +golang.org/x/exp v0.0.0-20231219180239-dc181d75b848/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= diff --git a/main.go b/main.go index f0a7f3a..7836e99 100644 --- a/main.go +++ b/main.go @@ -7,10 +7,12 @@ import ( "net/http" "forgejo.merr.is/annika/isl-api/Controllers" + routes "forgejo.merr.is/annika/isl-api/Routes" "forgejo.merr.is/annika/isl-api/Services" "forgejo.merr.is/annika/isl-api/sql/powerItem" + "github.com/go-chi/chi/v5" + "github.com/go-chi/cors" "github.com/jackc/pgx/v4/pgxpool" - "github.com/julienschmidt/httprouter" "github.com/spf13/viper" ) @@ -24,8 +26,6 @@ func main() { deps := dependencies{} deps.initializeDependencies() - deps.router.HandlerFunc("GET", "/", index) - fmt.Printf("Preparing to listen on `:%v`\n", conf.HttpPort) err := http.ListenAndServe(fmt.Sprintf(":%v", conf.HttpPort), deps.router) log.Fatal(err) @@ -49,7 +49,7 @@ func setupConfig() { } type dependencies struct { - router *httprouter.Router + router *chi.Mux postgresConnection *pgxpool.Pool context context.Context powerItemQuerier *powerItem.DBQuerier @@ -60,15 +60,12 @@ type dependencies struct { func (d *dependencies) initializeDependencies() error { var err error - d.router = httprouter.New() - d.router.GlobalOPTIONS = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.Header.Get("Access-Control-Request-Method") != "" { - header := w.Header() - header.Set("Access-Control-Allow-Methods", header.Get("Allow")) - header.Set("Access-Control-Allow-Headers", "Cache-Control, Expires, Pragma") - header.Set("Access-Control-Allow-Origin", "*") - } - }) + d.router = chi.NewRouter() + d.router.Use(cors.Handler(cors.Options{ + AllowedOrigins: []string{"*"}, + AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, + AllowedHeaders: []string{"Cache-Control", "Expires", "Pragma"}, + })) d.context = context.Background() d.postgresConnection, err = pgxpool.Connect(d.context, conf.ConnectionString) if err != nil { @@ -76,17 +73,7 @@ func (d *dependencies) initializeDependencies() error { } d.powerItemQuerier = powerItem.NewQuerier(d.postgresConnection) d.powerItemService = Services.NewPowerItemService(d.powerItemQuerier) - d.powerItemController = Controllers.NewPowerItemController(d.router, d.powerItemService) + d.powerItemController = Controllers.NewPowerItemController(d.powerItemService) + d.router.Mount("/powerItems", routes.SetupPowerItemRoutes(*d.powerItemController)) return nil } - -func MiddleCORS(next httprouter.Handle) httprouter.Handle { - return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - w.Header().Set("Access-Control-Allow-Origin", "*") - next(w, r, ps) - } -} - -func index(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, "Index") -}