commit 4335fd5caea808fd4d3b5aea594080b06b6156b4 Author: = Date: Tue Sep 23 09:35:10 2025 +0200 Add initial project structure with database connection and routing setup - Create .env.example and .gitignore to manage environment variables - Implement database connection logic in bd.go - Define project model and data retrieval functions in projet.go - Set up HTTP routes for project management in routes/projet.go - Add main entry point in main.go to start the server diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e69de29 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2eea525 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.env \ No newline at end of file diff --git a/bd/bd.go b/bd/bd.go new file mode 100644 index 0000000..7090e86 --- /dev/null +++ b/bd/bd.go @@ -0,0 +1,38 @@ +package bd + +import ( + "database/sql" + "log" + "os" + + "github.com/go-sql-driver/mysql" + "github.com/joho/godotenv" +) + +var db *sql.DB + +func GetDB() *sql.DB { + + if db == nil { + errenv := godotenv.Load() + if errenv != nil { + log.Fatal("Error loading .env file") + } + // Capture connection properties. + cfg := mysql.NewConfig() + cfg.User = os.Getenv("DB_USER") + cfg.Passwd = os.Getenv("DB_PASS") + cfg.Net = "tcp" + cfg.Addr = os.Getenv("DB_HOST") + cfg.DBName = os.Getenv("DB_NAME") + + // Get a database handle. + var err error + db, err = sql.Open("mysql", cfg.FormatDSN()) + if err != nil { + log.Fatal(err) + } + + } + return db +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ff34078 --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module api_serveurless_go + +go 1.25.1 + +require ( + github.com/go-sql-driver/mysql v1.9.3 + github.com/joho/godotenv v1.5.1 +) + +require filippo.io/edwards25519 v1.1.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..b380070 --- /dev/null +++ b/go.sum @@ -0,0 +1,6 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= +github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= diff --git a/main.go b/main.go new file mode 100644 index 0000000..1287542 --- /dev/null +++ b/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "api_serveurless_go/routes" + "net/http" +) + +func main() { + // Configuration des routes + routes.SetupRoutes() + + // Démarrage du serveur + http.ListenAndServe(":3000", nil) +} diff --git a/requette/projet.go b/requette/projet.go new file mode 100644 index 0000000..1b81cfe --- /dev/null +++ b/requette/projet.go @@ -0,0 +1,62 @@ +package requette + +import ( + "api_serveurless_go/bd" + "database/sql" + "log" +) + +type Projet struct { + Id int `json:"id"` + Name string `json:"name"` + ShortDescription string `json:"shortdescription"` +} + +func GetAllProjets() []Projet { + db := bd.GetDB() + stmt, err := db.Prepare("SELECT * FROM projet") + if err != nil { + log.Fatal(err) + } + row, err := stmt.Query() + defer stmt.Close() + if err != nil { + log.Fatal(err) + } + + return hydrateProjets(row) + +} + +func GetProjetByID(id int) Projet { + db := bd.GetDB() + stmt, err := db.Prepare("SELECT * FROM projet WHERE id = ?") + if err != nil { + log.Fatal(err) + } + row := stmt.QueryRow(id) + defer stmt.Close() + return hydrateProjet(row) +} + +func hydrateProjet(row *sql.Row) Projet { + var projet Projet + err := row.Scan(&projet.Id, &projet.Name, &projet.ShortDescription) + if err != nil { + log.Fatal(err) + } + return projet +} + +func hydrateProjets(rows *sql.Rows) []Projet { + var projets []Projet + for rows.Next() { + var projet Projet + err := rows.Scan(&projet.Id, &projet.Name, &projet.ShortDescription) + if err != nil { + log.Fatal(err) + } + projets = append(projets, projet) + } + return projets +} diff --git a/routes/projet.go b/routes/projet.go new file mode 100644 index 0000000..9dc8b2f --- /dev/null +++ b/routes/projet.go @@ -0,0 +1,62 @@ +package routes + +import ( + "api_serveurless_go/requette" + "encoding/json" + "fmt" + "net/http" + "strconv" + "strings" +) + +// SetupRoutes configure toutes les routes de l'application +func SetupRoutes() { + http.HandleFunc("/", homeHandler) + http.HandleFunc("/api/projets", projetsHandler) + http.HandleFunc("/api/projet/", projetHandler) +} + +// homeHandler gère la route racine +func homeHandler(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Welcome to my website!") +} + +// projetsHandler gère la liste des projets +func projetsHandler(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case "GET": + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(requette.GetAllProjets()) + case "POST": + fmt.Fprintf(w, "Créer un nouveau projet") + default: + http.Error(w, "Méthode non autorisée", http.StatusMethodNotAllowed) + } +} + +// projetHandler gère les actions sur un projet spécifique +func projetHandler(w http.ResponseWriter, r *http.Request) { + id := strings.TrimPrefix(r.URL.Path, "/api/projet/") + if id == "" { + http.Error(w, "ID manquant", http.StatusBadRequest) + return + } + idInt, err := strconv.Atoi(id) + if err != nil { + http.Error(w, "ID invalide", http.StatusBadRequest) + return + } + switch r.Method { + case "GET": + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(requette.GetProjetByID(idInt)) + case "PUT": + fmt.Fprintf(w, "Modifier le projet %d", idInt) + case "DELETE": + fmt.Fprintf(w, "Supprimer le projet %d", idInt) + default: + http.Error(w, "Méthode non autorisée", http.StatusMethodNotAllowed) + } +}