...
1 package main
2
3 import (
4 "context"
5 "io"
6 "log"
7 "net/http"
8 "os"
9
10 "github.com/jackc/pgx/v5"
11 "github.com/jackc/pgx/v5/pgxpool"
12 )
13
14 var db *pgxpool.Pool
15
16 func getUrlHandler(w http.ResponseWriter, req *http.Request) {
17 var url string
18 err := db.QueryRow(context.Background(), "select url from shortened_urls where id=$1", req.URL.Path).Scan(&url)
19 switch err {
20 case nil:
21 http.Redirect(w, req, url, http.StatusSeeOther)
22 case pgx.ErrNoRows:
23 http.NotFound(w, req)
24 default:
25 http.Error(w, "Internal server error", http.StatusInternalServerError)
26 }
27 }
28
29 func putUrlHandler(w http.ResponseWriter, req *http.Request) {
30 id := req.URL.Path
31 var url string
32 if body, err := io.ReadAll(req.Body); err == nil {
33 url = string(body)
34 } else {
35 http.Error(w, "Internal server error", http.StatusInternalServerError)
36 return
37 }
38
39 if _, err := db.Exec(context.Background(), `insert into shortened_urls(id, url) values ($1, $2)
40 on conflict (id) do update set url=excluded.url`, id, url); err == nil {
41 w.WriteHeader(http.StatusOK)
42 } else {
43 http.Error(w, "Internal server error", http.StatusInternalServerError)
44 }
45 }
46
47 func deleteUrlHandler(w http.ResponseWriter, req *http.Request) {
48 if _, err := db.Exec(context.Background(), "delete from shortened_urls where id=$1", req.URL.Path); err == nil {
49 w.WriteHeader(http.StatusOK)
50 } else {
51 http.Error(w, "Internal server error", http.StatusInternalServerError)
52 }
53 }
54
55 func urlHandler(w http.ResponseWriter, req *http.Request) {
56 switch req.Method {
57 case "GET":
58 getUrlHandler(w, req)
59
60 case "PUT":
61 putUrlHandler(w, req)
62
63 case "DELETE":
64 deleteUrlHandler(w, req)
65
66 default:
67 w.Header().Add("Allow", "GET, PUT, DELETE")
68 w.WriteHeader(http.StatusMethodNotAllowed)
69 }
70 }
71
72 func main() {
73 poolConfig, err := pgxpool.ParseConfig(os.Getenv("DATABASE_URL"))
74 if err != nil {
75 log.Fatalln("Unable to parse DATABASE_URL:", err)
76 }
77
78 db, err = pgxpool.NewWithConfig(context.Background(), poolConfig)
79 if err != nil {
80 log.Fatalln("Unable to create connection pool:", err)
81 }
82
83 http.HandleFunc("/", urlHandler)
84
85 log.Println("Starting URL shortener on localhost:8080")
86 err = http.ListenAndServe("localhost:8080", nil)
87 if err != nil {
88 log.Fatalln("Unable to start web server:", err)
89 }
90 }
91
View as plain text