Skip to content

Commit

Permalink
Added /v1/user POST endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
Kelby Amandy committed Aug 22, 2024
1 parent 4367cb7 commit 9ef58b4
Showing 14 changed files with 296 additions and 9 deletions.
14 changes: 14 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# --- Loading .env vars ---
ifneq (,$(wildcard ./.env))
include .env
export
endif

# --- Make targets ---
run:
@./bin/gogreggator

@@ -6,3 +13,10 @@ build:

test:
@go test -v ./...

db-up:
@cd internal/sql/schema && goose postgres $(DATABASE_URL) up

db-down:
@cd internal/sql/schema && goose postgres $(DATABASE_URL) down

48 changes: 42 additions & 6 deletions cmd/app/main.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,65 @@
package main

import (
"database/sql"
"errors"
"log"
"net/http"
"os"

"github.com/joho/godotenv"
"github.com/kelbwah/gogreggator/internal/database"
"github.com/kelbwah/gogreggator/internal/handlers"
"github.com/kelbwah/gogreggator/internal/types"
_ "github.com/lib/pq"
)

func main() {
if err := godotenv.Load(".env"); err != nil {
log.Fatalf("Error loading .env vars: %v", err)
godotenv.Load(".env")
env, err := initVars()
if err != nil {
log.Fatalf("Error loading var(s): %s\n", err.Error())
}
port := os.Getenv("PORT")

db, err := sql.Open("postgres", env["dbUrl"])
if err != nil {
log.Fatalf("Database Error: %s\n", err.Error())
}

dbQueries := database.New(db)
apiCfg := &types.APIConfig{
DB: dbQueries,
}

mux := http.NewServeMux()
handlers.HandlersInit(mux)
handlers.HandlersInit(mux, apiCfg)

server := &http.Server{
Addr: ":" + port,
Addr: ":" + env["port"],
Handler: mux,
}

log.Printf("Listening on port ':%s'\n", port)
log.Printf("Listening on port ':%s'\n", env["port"])
if err := server.ListenAndServe(); err != nil {
log.Fatalf("Server failed to start: %v\n", err)
}
}

func initVars() (map[string]string, error) {
varMap := make(map[string]string)

port := os.Getenv("PORT")
if port == "" {
return nil, errors.New("PORT environment variable is not set")
}

dbUrl := os.Getenv("DATABASE_URL")
if dbUrl == "" {
return nil, errors.New("DATABASE_URL environment variable is not set")
}

varMap["port"] = port
varMap["dbUrl"] = dbUrl

return varMap, nil
}
63 changes: 63 additions & 0 deletions cmd/app/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package main

import (
"os"
"reflect"
"testing"
)

func setEnvs(envs map[string]string) (closer func()) {
originalEnvs := map[string]string{}

for name, value := range envs {
if originalValue, ok := os.LookupEnv(name); ok {
originalEnvs[name] = originalValue
}
_ = os.Setenv(name, value)
}

return func() {
for name := range envs {
_ = os.Unsetenv(name)
}
}
}

func TestInitVars(t *testing.T) {
t.Run("All env vars set correctly", func(t *testing.T) {
curEnvs := setEnvs(map[string]string{
"PORT": "6969",
"DATABASE_URL": "testing url",
})
defer curEnvs()

expected := map[string]string{
"port": "6969",
"dbUrl": "testing url",
}

result, _ := initVars()
if reflect.DeepEqual(result, expected) == false {
t.Fatalf("Expected %v, got %v\n", expected, result)
}
})

t.Run("One env vars set correctly", func(t *testing.T) {
curEnvs := setEnvs(map[string]string{
"PORT": "6969",
})
defer curEnvs()

result, _ := initVars()
if result != nil {
t.Fatalf("Expected %v, got %v\n", nil, result)
}
})

t.Run("No env vars set correctly", func(t *testing.T) {
result, _ := initVars()
if result != nil {
t.Fatalf("Expected %v, got %v\n", nil, result)
}
})
}
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -2,4 +2,8 @@ module github.com/kelbwah/gogreggator

go 1.22.1

require github.com/joho/godotenv v1.5.1 // indirect
require (
github.com/google/uuid v1.6.0 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/lib/pq v1.10.9 // indirect
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
31 changes: 31 additions & 0 deletions internal/database/db.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions internal/database/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 43 additions & 0 deletions internal/database/users.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 10 additions & 2 deletions internal/handlers/handlers.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
package handlers

import "net/http"
import (
"net/http"

func HandlersInit(mux *http.ServeMux) {
"github.com/kelbwah/gogreggator/internal/types"
)

func HandlersInit(mux *http.ServeMux, apiCfg *types.APIConfig) {
/* -- GET ENDPOINTS -- */
mux.HandleFunc("GET /v1/healthz", readinessHandler)
mux.HandleFunc("GET /v1/err", errorHandler)

/* -- POST ENDPOINTS -- */
mux.HandleFunc("POST /v1/users", apiCfg.HandleUsersCreate)
}
4 changes: 4 additions & 0 deletions internal/sql/queries/users.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- name: CreateUser :one
INSERT INTO users (id, created_at, updated_at, name)
VALUES ($1, $2, $3, $4)
RETURNING *;
10 changes: 10 additions & 0 deletions internal/sql/schema/001_users.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- +goose Up
CREATE TABLE IF NOT EXISTS users (
id UUID PRIMARY KEY,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL,
name TEXT NOT NULL
);

-- +goose Down
DROP TABLE users;
44 changes: 44 additions & 0 deletions internal/types/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package types

import (
"encoding/json"
"net/http"
"time"

"github.com/google/uuid"
"github.com/kelbwah/gogreggator/internal/database"
"github.com/kelbwah/gogreggator/utils"
)

type APIConfig struct {
DB *database.Queries
}

func (cfg *APIConfig) HandleUsersCreate(w http.ResponseWriter, r *http.Request) {
type parameters struct {
Name string `json:"name"`
}

params := parameters{}
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&params)
if err != nil {
utils.RespondWithError(w, http.StatusInternalServerError, "Couldn't decode parameters")
return
}

userParams := database.CreateUserParams{
ID: uuid.New(),
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
Name: params.Name,
}

createdUser, err := cfg.DB.CreateUser(r.Context(), userParams)
if err != nil {
utils.RespondWithError(w, http.StatusInternalServerError, err.Error())
return
}

utils.RespondWithJSON(w, http.StatusCreated, createdUser)
}
8 changes: 8 additions & 0 deletions sqlc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version: "2"
sql:
- schema: "internal/sql/schema"
queries: "internal/sql/queries"
engine: "postgresql"
gen:
go:
out: "internal/database"
File renamed without changes.

0 comments on commit 9ef58b4

Please sign in to comment.