HUGE progress
This commit is contained in:
parent
a9623fa7be
commit
c3610ac1e4
10 changed files with 265 additions and 58 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,2 +1,2 @@
|
|||
secret-santa
|
||||
*.db
|
||||
*.db
|
||||
.idea/
|
||||
|
|
31
cmd/secret-santa/main.go
Normal file
31
cmd/secret-santa/main.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/app"
|
||||
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/config"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
dbConnection, err := sql.Open("sqlite3", "./test.db")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Println("Database sucessfully connected")
|
||||
|
||||
appConfig := config.NewAppConfig(nil, nil)
|
||||
application := app.NewApp(dbConnection, &appConfig)
|
||||
|
||||
log.Printf("Listening on http://%s", appConfig.GenerateIP())
|
||||
|
||||
log.Fatal(
|
||||
http.ListenAndServe(
|
||||
appConfig.GenerateIP(),
|
||||
application.Router(),
|
||||
),
|
||||
)
|
||||
}
|
32
internal/app/app.go
Normal file
32
internal/app/app.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/config"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
Config config.AppConfig
|
||||
DB *sql.DB
|
||||
}
|
||||
|
||||
func NewApp(db *sql.DB, appConfig *config.AppConfig) *App {
|
||||
defaultConfig := config.NewAppConfig(nil, nil)
|
||||
if appConfig == nil {
|
||||
appConfig = &defaultConfig
|
||||
}
|
||||
|
||||
return &App{
|
||||
Config: *appConfig,
|
||||
DB: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) Router() http.Handler {
|
||||
router := http.NewServeMux()
|
||||
|
||||
AddRoutes(router, a.DB)
|
||||
|
||||
return router
|
||||
}
|
14
internal/app/routes.go
Normal file
14
internal/app/routes.go
Normal file
|
@ -0,0 +1,14 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/handlers"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func AddRoutes(router *http.ServeMux, db *sql.DB) {
|
||||
router.HandleFunc("GET /users/{id}", handlers.HandleGetUsersByID(db))
|
||||
router.HandleFunc("GET /users/", handlers.HandleGetUsers(db))
|
||||
router.HandleFunc("POST /users/", handlers.HandleCreateUser(db))
|
||||
router.HandleFunc("DELETE /users/{id}", handlers.HandleDeleteUser(db))
|
||||
}
|
29
internal/config/config.go
Normal file
29
internal/config/config.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package config
|
||||
|
||||
import "fmt"
|
||||
|
||||
type AppConfig struct {
|
||||
ListenIP string `json:"listen_ip"`
|
||||
ListenPort int `json:"listen_port"`
|
||||
}
|
||||
|
||||
func (c *AppConfig) GenerateIP() string {
|
||||
return fmt.Sprintf("%s:%d", c.ListenIP, c.ListenPort)
|
||||
}
|
||||
|
||||
func NewAppConfig(port *int, ip *string) AppConfig {
|
||||
defaultPort := 8080
|
||||
defaultIp := "127.0.0.1"
|
||||
|
||||
if port == nil {
|
||||
port = &defaultPort
|
||||
}
|
||||
if ip == nil {
|
||||
ip = &defaultIp
|
||||
}
|
||||
|
||||
return AppConfig{
|
||||
ListenIP: *ip,
|
||||
ListenPort: *port,
|
||||
}
|
||||
}
|
93
internal/handlers/user_handler.go
Normal file
93
internal/handlers/user_handler.go
Normal file
|
@ -0,0 +1,93 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/queries"
|
||||
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/types"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func HandleGetUsers(db *sql.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := context.Background()
|
||||
query := queries.New(db)
|
||||
|
||||
users, err := query.GetUsers(ctx)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, 500, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(users) == 0 {
|
||||
users = []queries.User{}
|
||||
}
|
||||
|
||||
writeJSONResponse(w, 200, types.JsonResponse[[]queries.User]{Data: users})
|
||||
}
|
||||
}
|
||||
func HandleGetUsersByID(db *sql.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := context.Background()
|
||||
query := queries.New(db)
|
||||
|
||||
id, err := parseIDFromURL(r)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, 500, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
user, err := query.GetUserId(ctx, id)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
writeErrorResponse(w, 404, "User not found")
|
||||
return
|
||||
}
|
||||
writeErrorResponse(w, 500, err.Error())
|
||||
return
|
||||
}
|
||||
writeJSONResponse(w, 200, types.JsonResponse[queries.User]{Data: user})
|
||||
}
|
||||
}
|
||||
|
||||
func HandleCreateUser(db *sql.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := context.Background()
|
||||
query := queries.New(db)
|
||||
|
||||
var createUser queries.CreateUserParams
|
||||
err := readJSONRequest(r, &createUser)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, 500, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
user, err := query.CreateUser(ctx, createUser)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, 500, err.Error())
|
||||
return
|
||||
}
|
||||
writeJSONResponse(w, 201, types.JsonResponse[queries.User]{Data: user})
|
||||
}
|
||||
}
|
||||
|
||||
func HandleDeleteUser(db *sql.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := context.Background()
|
||||
query := queries.New(db)
|
||||
|
||||
id, err := parseIDFromURL(r)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, 500, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
err = query.DeleteUser(ctx, id)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, 500, err.Error())
|
||||
return
|
||||
}
|
||||
writeJSONResponse(w, 204, nil)
|
||||
}
|
||||
}
|
38
internal/handlers/utils.go
Normal file
38
internal/handlers/utils.go
Normal file
|
@ -0,0 +1,38 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/types"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func writeJSONResponse(w http.ResponseWriter, statusCode int, data interface{}) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(statusCode)
|
||||
err := json.NewEncoder(w).Encode(data)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to write response. Error: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeErrorResponse(w http.ResponseWriter, statusCode int, message string) {
|
||||
writeJSONResponse(w, statusCode, types.ErrorResponse{Message: message})
|
||||
}
|
||||
|
||||
func readJSONRequest(r *http.Request, data interface{}) error {
|
||||
err := json.NewDecoder(r.Body).Decode(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseIDFromURL(r *http.Request) (int64, error) {
|
||||
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return id, nil
|
||||
}
|
|
@ -9,8 +9,9 @@ import (
|
|||
"context"
|
||||
)
|
||||
|
||||
const createUser = `-- name: CreateUser :exec
|
||||
const createUser = `-- name: CreateUser :one
|
||||
INSERT INTO users (id, email, first_name, last_name) VALUES (NULL, ?, ?, ?)
|
||||
RETURNING id, first_name, last_name, email
|
||||
`
|
||||
|
||||
type CreateUserParams struct {
|
||||
|
@ -19,8 +20,24 @@ type CreateUserParams struct {
|
|||
LastName string `json:"last_name"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) error {
|
||||
_, err := q.db.ExecContext(ctx, createUser, arg.Email, arg.FirstName, arg.LastName)
|
||||
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, error) {
|
||||
row := q.db.QueryRowContext(ctx, createUser, arg.Email, arg.FirstName, arg.LastName)
|
||||
var i User
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.FirstName,
|
||||
&i.LastName,
|
||||
&i.Email,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteUser = `-- name: DeleteUser :exec
|
||||
DELETE FROM users WHERE id = ?
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteUser(ctx context.Context, id int64) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteUser, id)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
51
main.go
51
main.go
|
@ -1,51 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/queries"
|
||||
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/types"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
var dbConnection *sql.DB
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
dbConnection, err = sql.Open("sqlite3", "./test.db")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Println("Database sucessfully connected")
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
|
||||
log.Println("Created database connection")
|
||||
|
||||
router := http.NewServeMux()
|
||||
|
||||
router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
query := queries.New(dbConnection)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
users, err := query.GetUsers(ctx)
|
||||
if err != nil {
|
||||
w.WriteHeader(404)
|
||||
log.Printf("Failed to get all users: %s\n", err.Error())
|
||||
json.NewEncoder(w).Encode(types.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
if len(users) == 0 {
|
||||
users = make([]queries.User, 0)
|
||||
}
|
||||
json.NewEncoder(w).Encode(types.JsonResponse[[]queries.User]{Data: users})
|
||||
})
|
||||
|
||||
log.Fatal(http.ListenAndServe(":8080", router))
|
||||
}
|
|
@ -5,5 +5,9 @@ WHERE id = ? LIMIT 1;
|
|||
-- name: GetUsers :many
|
||||
SELECT * FROM users;
|
||||
|
||||
-- name: CreateUser :exec
|
||||
INSERT INTO users (id, email, first_name, last_name) VALUES (NULL, ?, ?, ?);
|
||||
-- name: CreateUser :one
|
||||
INSERT INTO users (id, email, first_name, last_name) VALUES (NULL, ?, ?, ?)
|
||||
RETURNING *;
|
||||
|
||||
-- name: DeleteUser :exec
|
||||
DELETE FROM users WHERE id = ?;
|
Loading…
Reference in a new issue