package main import ( "database/sql" "embed" "io" "log" "net/http" "net/url" "os" "strings" "github.com/go-chi/chi" "github.com/go-chi/cors" "github.com/joho/godotenv" "github.com/bootdotdev/learn-cicd-starter/internal/database" _ "github.com/go-sql-driver/mysql" ) type apiConfig struct { DB *database.Queries } //go:embed static/* var staticFiles embed.FS func main() { err := godotenv.Load(".env") if err != nil { log.Printf("warning: assuming default configuration. .env unreadable: %v", err) } port := os.Getenv("PORT") if port == "" { log.Fatal("PORT environment variable is not set") } apiCfg := apiConfig{} dbURL := os.Getenv("DATABASE_URL") if dbURL == "" { log.Println("DATABASE_URL environment variable is not set") log.Println("Running without CRUD endpoints") } else { parsedURL, err := addParseTimeParam(dbURL) if err != nil { log.Fatal(err) } db, err := sql.Open("mysql", parsedURL) if err != nil { log.Fatal(err) } dbQueries := database.New(db) apiCfg.DB = dbQueries log.Println("Connected to database!") } router := chi.NewRouter() router.Use(cors.Handler(cors.Options{ AllowedOrigins: []string{"https://*", "http://*"}, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedHeaders: []string{"*"}, ExposedHeaders: []string{"Link"}, AllowCredentials: false, MaxAge: 300, })) router.Get("/", func(w http.ResponseWriter, r *http.Request) { f, err := staticFiles.Open("static/index.html") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer f.Close() if _, err := io.Copy(w, f); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }) v1Router := chi.NewRouter() if apiCfg.DB != nil { v1Router.Post("/users", apiCfg.handlerUsersCreate) v1Router.Get("/users", apiCfg.middlewareAuth(apiCfg.handlerUsersGet)) v1Router.Get("/notes", apiCfg.middlewareAuth(apiCfg.handlerNotesGet)) v1Router.Post("/notes", apiCfg.middlewareAuth(apiCfg.handlerNotesCreate)) } v1Router.Get("/healthz", handlerReadiness) router.Mount("/v1", v1Router) srv := &http.Server{ Addr: ":" + port, Handler: router, } log.Printf("Serving on port: %s\n", port) log.Fatal(srv.ListenAndServe()) } func addParseTimeParam(input string) (string, error) { const dummyScheme = "http://" if !strings.Contains(input, dummyScheme) { input = "http://" + input } u, err := url.Parse(input) if err != nil { return "", err } q := u.Query() q.Add("parseTime", "true") u.RawQuery = q.Encode() returnUrl := u.String() returnUrl = strings.TrimPrefix(returnUrl, dummyScheme) return returnUrl, nil }