From de5f090a9cb9513e9d7b2ed7c382de606fe5b7ec Mon Sep 17 00:00:00 2001 From: Darius Rapalis Date: Tue, 11 Mar 2025 19:08:34 +0200 Subject: [PATCH] creating chirps! --- internal/database/CreateChirp.sql.go | 36 +++++++++++++++ internal/database/models.go | 8 ++++ main.go | 68 +++++++++++++++++++--------- sql/queries/CreateChirp.sql | 4 ++ sql/schema/002_chirps.sql | 11 +++++ 5 files changed, 105 insertions(+), 22 deletions(-) create mode 100644 internal/database/CreateChirp.sql.go create mode 100644 sql/queries/CreateChirp.sql create mode 100644 sql/schema/002_chirps.sql diff --git a/internal/database/CreateChirp.sql.go b/internal/database/CreateChirp.sql.go new file mode 100644 index 0000000..19de584 --- /dev/null +++ b/internal/database/CreateChirp.sql.go @@ -0,0 +1,36 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.28.0 +// source: CreateChirp.sql + +package database + +import ( + "context" + + "github.com/google/uuid" +) + +const createChirp = `-- name: CreateChirp :one +INSERT INTO chirps (id, created_at, updated_at, body, user_id) +VALUES (gen_random_uuid(), NOW(), NOW(), $1, $2) +RETURNING id, created_at, updated_at, body, user_id +` + +type CreateChirpParams struct { + Body string + UserID uuid.UUID +} + +func (q *Queries) CreateChirp(ctx context.Context, arg CreateChirpParams) (Chirp, error) { + row := q.db.QueryRowContext(ctx, createChirp, arg.Body, arg.UserID) + var i Chirp + err := row.Scan( + &i.ID, + &i.CreatedAt, + &i.UpdatedAt, + &i.Body, + &i.UserID, + ) + return i, err +} diff --git a/internal/database/models.go b/internal/database/models.go index 40b659e..768de98 100644 --- a/internal/database/models.go +++ b/internal/database/models.go @@ -10,6 +10,14 @@ import ( "github.com/google/uuid" ) +type Chirp struct { + ID uuid.UUID + CreatedAt time.Time + UpdatedAt time.Time + Body string + UserID uuid.UUID +} + type User struct { ID uuid.UUID CreatedAt time.Time diff --git a/main.go b/main.go index de65ebb..9a8bf6a 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,7 @@ import ( "database/sql" "encoding/json" "fmt" + "github.com/google/uuid" "github.com/joho/godotenv" _ "github.com/lib/pq" "github.com/rdarius/go-http-server/internal/database" @@ -74,6 +75,46 @@ func fileServerHandler() http.Handler { return http.StripPrefix("/app", fileServer) } +func postChirpsHandler(cfg *apiConfig) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + type parameters struct { + Body string `json:"body"` + UserID uuid.UUID `json:"user_id"` + } + + params := parameters{} + err := json.NewDecoder(r.Body).Decode(¶ms) + if err != nil { + httpResponse.JSONHandler(w, http.StatusBadRequest, `{"error": "Failed to parse request body"}`) + return + } + + chirp, err := validateChirp(params.Body) + if err != nil { + httpResponse.JSONHandler(w, http.StatusBadRequest, fmt.Sprintf(`{"error": "%s"}`, err.Error())) + return + } + + newChirp, err := cfg.db.CreateChirp(context.Background(), database.CreateChirpParams{ + Body: chirp, + UserID: params.UserID, + }) + if err != nil { + httpResponse.JSONHandler(w, http.StatusInternalServerError, fmt.Sprintf(`{"error": "%s"}`, err.Error())) + return + } + + jsonData := fmt.Sprintf(`{ + "id": "%s", + "created_at": "%s", + "updated_at": "%s", + "body": "%s", + "user_id": "%s" + }`, newChirp.ID, newChirp.CreatedAt, newChirp.UpdatedAt, newChirp.Body, newChirp.UserID) + httpResponse.JSONHandler(w, http.StatusCreated, jsonData) + } +} + func postUsersHandler(cfg *apiConfig) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { type parameters struct { @@ -103,36 +144,19 @@ func postUsersHandler(cfg *apiConfig) http.HandlerFunc { } } -func validateChirpHandler(w http.ResponseWriter, r *http.Request) { - type parameters struct { - Body string `json:"body"` - } - +func validateChirp(chirp string) (string, error) { profaneWords := []string{"kerfuffle", "sharbert", "fornax"} - decoder := json.NewDecoder(r.Body) - params := parameters{} - err := decoder.Decode(¶ms) - if err != nil { - httpResponse.SomethingWentWrong(w) - return + if len(chirp) > 140 { + return "", fmt.Errorf("chirp is too long") } - if len(params.Body) > 140 { - httpResponse.JSONHandler(w, http.StatusBadRequest, `{"error": "Chirp is too long"}`) - return - } - - chirp := params.Body - for _, word := range profaneWords { - // Use word boundaries (\b) to match whole words and ignore punctuation re := regexp.MustCompile(`(?i)\b` + regexp.QuoteMeta(word) + `\b`) chirp = re.ReplaceAllString(chirp, "****") } - httpResponse.JSONHandler(w, http.StatusOK, fmt.Sprintf(`{"cleaned_body": "%s"}`, chirp)) - return + return chirp, nil } func main() { @@ -159,8 +183,8 @@ func main() { mux.HandleFunc("GET /api/healthz", readinessHandler) mux.HandleFunc("GET /api/metrics", metricsHandler(apiCfg)) mux.HandleFunc("POST /api/reset", resetMetricsHandler(apiCfg)) - mux.HandleFunc("POST /api/validate_chirp", validateChirpHandler) mux.HandleFunc("POST /api/users", postUsersHandler(apiCfg)) + mux.HandleFunc("POST /api/chirps", postChirpsHandler(apiCfg)) mux.HandleFunc("GET /admin/metrics", adminMetricsHandler(apiCfg)) mux.HandleFunc("POST /admin/reset", resetMetricsHandler(apiCfg)) diff --git a/sql/queries/CreateChirp.sql b/sql/queries/CreateChirp.sql new file mode 100644 index 0000000..ca3e938 --- /dev/null +++ b/sql/queries/CreateChirp.sql @@ -0,0 +1,4 @@ +-- name: CreateChirp :one +INSERT INTO chirps (id, created_at, updated_at, body, user_id) +VALUES (gen_random_uuid(), NOW(), NOW(), $1, $2) +RETURNING *; \ No newline at end of file diff --git a/sql/schema/002_chirps.sql b/sql/schema/002_chirps.sql new file mode 100644 index 0000000..9f0f099 --- /dev/null +++ b/sql/schema/002_chirps.sql @@ -0,0 +1,11 @@ +-- +goose Up +CREATE TABLE chirps( + id UUID PRIMARY KEY, + created_at TIMESTAMP not null DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP not null DEFAULT CURRENT_TIMESTAMP, + body TEXT not null UNIQUE, + user_id UUID not null REFERENCES users(id) ON DELETE CASCADE +); + +-- +goose Down +DROP TABLE chirps; \ No newline at end of file