feat: Initialize project with MySQL database and API for managing projects and technologies
- Created SQL script to set up database tables for projects and technologies. - Added Docker Compose configuration for application and MySQL service. - Implemented API endpoints for CRUD operations on technologies. - Defined data types for projects and technologies. - Established routing for API endpoints.
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
DB_USER=""
|
||||||
|
DB_PASS=""
|
||||||
|
DB_HOST=""
|
||||||
|
DB_NAME=""
|
||||||
+2
-1
@@ -1 +1,2 @@
|
|||||||
.env
|
.env
|
||||||
|
/vendor
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
FROM golang:1.21
|
||||||
|
WORKDIR /app
|
||||||
|
COPY . .
|
||||||
|
RUN go mod tidy && go build -o main .
|
||||||
|
EXPOSE 3000
|
||||||
|
CMD ["./main"]
|
||||||
Binary file not shown.
@@ -1,38 +1,37 @@
|
|||||||
package bd
|
package bd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"github.com/go-sql-driver/mysql"
|
||||||
"github.com/go-sql-driver/mysql"
|
"github.com/joho/godotenv"
|
||||||
"github.com/joho/godotenv"
|
)
|
||||||
)
|
|
||||||
|
var db *sql.DB
|
||||||
var db *sql.DB
|
|
||||||
|
func GetDB() *sql.DB {
|
||||||
func GetDB() *sql.DB {
|
|
||||||
|
if db == nil {
|
||||||
if db == nil {
|
errenv := godotenv.Load()
|
||||||
errenv := godotenv.Load()
|
if errenv != nil {
|
||||||
if errenv != nil {
|
log.Println("No .env file found; using environment variables")
|
||||||
log.Fatal("Error loading .env file")
|
}
|
||||||
}
|
// Capture connection properties.
|
||||||
// Capture connection properties.
|
cfg := mysql.NewConfig()
|
||||||
cfg := mysql.NewConfig()
|
cfg.User = os.Getenv("DB_USER")
|
||||||
cfg.User = os.Getenv("DB_USER")
|
cfg.Passwd = os.Getenv("DB_PASS")
|
||||||
cfg.Passwd = os.Getenv("DB_PASS")
|
cfg.Net = "tcp"
|
||||||
cfg.Net = "tcp"
|
cfg.Addr = os.Getenv("DB_HOST")
|
||||||
cfg.Addr = os.Getenv("DB_HOST")
|
cfg.DBName = os.Getenv("DB_NAME")
|
||||||
cfg.DBName = os.Getenv("DB_NAME")
|
|
||||||
|
// Get a database handle.
|
||||||
// Get a database handle.
|
var err error
|
||||||
var err error
|
db, err = sql.Open("mysql", cfg.FormatDSN())
|
||||||
db, err = sql.Open("mysql", cfg.FormatDSN())
|
if err != nil {
|
||||||
if err != nil {
|
log.Fatal(err)
|
||||||
log.Fatal(err)
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
}
|
return db
|
||||||
return db
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
DROP TABLE IF EXISTS projet;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS technologie;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS projet_technologie;
|
||||||
|
|
||||||
|
create table
|
||||||
|
projet (
|
||||||
|
id int primary key auto_increment,
|
||||||
|
name varchar(255) not null,
|
||||||
|
shortdescriptionfr text not null,
|
||||||
|
longdescriptionfr text not null,
|
||||||
|
shortdescriptionen text not null,
|
||||||
|
longdescriptionen text not null,
|
||||||
|
linkGithub varchar(255),
|
||||||
|
linkWeb varchar(255),
|
||||||
|
datec date not null
|
||||||
|
);
|
||||||
|
|
||||||
|
create table
|
||||||
|
technologie (
|
||||||
|
id int primary key auto_increment,
|
||||||
|
name varchar(255) not null
|
||||||
|
);
|
||||||
|
|
||||||
|
create table
|
||||||
|
projet_technologie (
|
||||||
|
projet_id int,
|
||||||
|
technologie_id int,
|
||||||
|
primary key (projet_id, technologie_id),
|
||||||
|
foreign key (projet_id) references projet (id) on delete cascade,
|
||||||
|
foreign key (technologie_id) references technologie (id) on delete cascade
|
||||||
|
);
|
||||||
|
|
||||||
|
insert into projet (name, shortdescriptionfr, longdescriptionfr, shortdescriptionen, longdescriptionen, linkGithub, linkWeb, datec) values
|
||||||
|
('Mon Portefolio', 'Un site web pour présenter mes projets et compétences.', 'Ce site web a été développé pour présenter mes projets personnels et professionnels, ainsi que mes compétences en développement web. Il utilise Go pour le backend et React pour le frontend.', 'A website to showcase my projects and skills.', 'This website was developed to showcase my personal and professional projects, as well as my web development skills. It uses Go for the backend and React for the frontend.', 'https://github.com/sylvain/portfolio', 'https://sylvain-portfolio.com', '2023-01-15');
|
||||||
|
insert into technologie (name) values
|
||||||
|
('Go'),
|
||||||
|
('React'),
|
||||||
|
('JavaScript'),
|
||||||
|
('HTML'),
|
||||||
|
('CSS');
|
||||||
|
|
||||||
|
insert into projet_technologie (projet_id, technologie_id) values
|
||||||
|
(1, 1),
|
||||||
|
(1, 2),
|
||||||
|
(1, 3),
|
||||||
|
(1, 4),
|
||||||
|
(1, 5);
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
command: ["sh", "-c", "sleep 6 && ./main"]
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: mysql:8.0
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||||
|
MYSQL_DATABASE: ${MYSQL_DATABASE}
|
||||||
|
MYSQL_USER: ${MYSQL_USER}
|
||||||
|
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- db_data:/var/lib/mysql
|
||||||
|
- ./create_table.sql:/docker-entrypoint-initdb.d/create_table.sql:ro
|
||||||
|
ports:
|
||||||
|
- "3306:3306"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db_data:
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
module api_serveurless_go
|
module api_serveurless_go
|
||||||
|
|
||||||
go 1.25.1
|
go 1.21.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/go-sql-driver/mysql v1.9.3
|
github.com/go-sql-driver/mysql v1.9.3
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"api_serveurless_go/routes"
|
"api_serveurless_go/routes"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Configuration des routes
|
// Configuration des routes
|
||||||
routes.SetupRoutes()
|
routes.SetupRoutes()
|
||||||
|
|
||||||
// Démarrage du serveur
|
// Démarrage du serveur
|
||||||
http.ListenAndServe(":3000", nil)
|
http.ListenAndServe(":3000", nil)
|
||||||
}
|
}
|
||||||
|
|||||||
+132
-62
@@ -1,62 +1,132 @@
|
|||||||
package requette
|
package requette
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"api_serveurless_go/bd"
|
"api_serveurless_go/bd"
|
||||||
"database/sql"
|
"api_serveurless_go/types"
|
||||||
"log"
|
"database/sql"
|
||||||
)
|
"log"
|
||||||
|
"strings"
|
||||||
type Projet struct {
|
)
|
||||||
Id int `json:"id"`
|
|
||||||
Name string `json:"name"`
|
func GetAllProjets(nb int,page int) types.Projets {
|
||||||
ShortDescription string `json:"shortdescription"`
|
db := bd.GetDB()
|
||||||
}
|
offset := (page - 1) * nb
|
||||||
|
stmt, err := db.Prepare("SELECT projet.id, projet.name, projet.shortdescriptionfr, GROUP_CONCAT(technologie.name SEPARATOR ',') as technologies FROM projet LEFT JOIN projet_technologie on projet.id = projet_technologie.projet_id LEFT JOIN technologie on projet_technologie.technologie_id = technologie.id GROUP BY projet.id, projet.name, projet.shortdescriptionfr LIMIT ? OFFSET ?")
|
||||||
func GetAllProjets() []Projet {
|
if err != nil {
|
||||||
db := bd.GetDB()
|
log.Fatal(err)
|
||||||
stmt, err := db.Prepare("SELECT * FROM projet")
|
}
|
||||||
if err != nil {
|
row, err := stmt.Query(nb, offset)
|
||||||
log.Fatal(err)
|
defer stmt.Close()
|
||||||
}
|
if err != nil {
|
||||||
row, err := stmt.Query()
|
log.Fatal(err)
|
||||||
defer stmt.Close()
|
}
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
stmt2, err := db.Prepare("SELECT count(*) FROM projet")
|
||||||
}
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
return hydrateProjets(row)
|
}
|
||||||
|
row2, err := stmt2.Query()
|
||||||
}
|
defer stmt2.Close()
|
||||||
|
if err != nil {
|
||||||
func GetProjetByID(id int) Projet {
|
log.Fatal(err)
|
||||||
db := bd.GetDB()
|
}
|
||||||
stmt, err := db.Prepare("SELECT * FROM projet WHERE id = ?")
|
var count int
|
||||||
if err != nil {
|
for row2.Next() {
|
||||||
log.Fatal(err)
|
err := row2.Scan(&count)
|
||||||
}
|
if err != nil {
|
||||||
row := stmt.QueryRow(id)
|
log.Fatal(err)
|
||||||
defer stmt.Close()
|
}
|
||||||
return hydrateProjet(row)
|
}
|
||||||
}
|
|
||||||
|
var projets types.Projets
|
||||||
func hydrateProjet(row *sql.Row) Projet {
|
projets.Projets = hydrateProjets(row)
|
||||||
var projet Projet
|
projets.Count = count
|
||||||
err := row.Scan(&projet.Id, &projet.Name, &projet.ShortDescription)
|
|
||||||
if err != nil {
|
return projets
|
||||||
log.Fatal(err)
|
|
||||||
}
|
}
|
||||||
return projet
|
|
||||||
}
|
func GetProjetByID(id int) types.ProjetFull {
|
||||||
|
db := bd.GetDB()
|
||||||
func hydrateProjets(rows *sql.Rows) []Projet {
|
stmt, err := db.Prepare("SELECT id, name, shortdescriptionfr, longdescriptionfr, shortdescriptionen, longdescriptionen, linkGithub, linkWeb FROM projet WHERE id = ?")
|
||||||
var projets []Projet
|
if err != nil {
|
||||||
for rows.Next() {
|
log.Fatal(err)
|
||||||
var projet Projet
|
}
|
||||||
err := rows.Scan(&projet.Id, &projet.Name, &projet.ShortDescription)
|
row := stmt.QueryRow(id)
|
||||||
if err != nil {
|
defer stmt.Close()
|
||||||
log.Fatal(err)
|
return hydrateProjet(row)
|
||||||
}
|
}
|
||||||
projets = append(projets, projet)
|
|
||||||
}
|
func hydrateProjet(row *sql.Row) types.ProjetFull {
|
||||||
return projets
|
var projet types.ProjetFull
|
||||||
}
|
err := row.Scan(&projet.Id, &projet.Name, &projet.ShortDescriptionFr, &projet.LongDescriptionFr, &projet.ShortDescriptionEn, &projet.LongDescriptionEn, &projet.LinkGithub, &projet.LinkWeb)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return projet
|
||||||
|
}
|
||||||
|
|
||||||
|
func hydrateProjets(rows *sql.Rows) []types.ProjetShort {
|
||||||
|
var projets []types.ProjetShort
|
||||||
|
for rows.Next() {
|
||||||
|
var projet types.ProjetShort
|
||||||
|
var techs sql.NullString
|
||||||
|
err := rows.Scan(&projet.Id, &projet.Name, &projet.ShortDescriptionFr, &techs)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if techs.Valid && techs.String != "" {
|
||||||
|
projet.Technologies = strings.Split(techs.String, ",")
|
||||||
|
} else {
|
||||||
|
projet.Technologies = []string{}
|
||||||
|
}
|
||||||
|
projets = append(projets, projet)
|
||||||
|
}
|
||||||
|
return projets
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateProjet(projet types.Projetcreate) *types.Projetcreate {
|
||||||
|
db := bd.GetDB()
|
||||||
|
stmt, err := db.Prepare("INSERT INTO projet (name, shortdescriptionfr, longdescriptionfr, shortdescriptionen, longdescriptionen, linkGithub, linkWeb, datec) VALUES (?, ?, '', '', '', '', '', CURDATE())")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = stmt.Exec(projet.Name, projet.ShortDescription)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer stmt.Close()
|
||||||
|
return &projet
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateProjet(projet types.ProjetFull) *types.ProjetFull {
|
||||||
|
db := bd.GetDB()
|
||||||
|
stmt, err := db.Prepare("UPDATE projet SET name = ?, shortdescriptionfr = ?, longdescriptionfr = ?, shortdescriptionen = ?, longdescriptionen = ?, linkGithub = ?, linkWeb = ? WHERE id = ?")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = stmt.Exec(projet.Name, projet.ShortDescriptionFr, projet.LongDescriptionFr, projet.ShortDescriptionEn, projet.LongDescriptionEn, projet.LinkGithub, projet.LinkWeb, projet.Id)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer stmt.Close()
|
||||||
|
return &projet
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteProjet(id int) bool {
|
||||||
|
db := bd.GetDB()
|
||||||
|
stmt, err := db.Prepare("DELETE FROM projet WHERE id = ?")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_, err = stmt.Exec(id)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer stmt.Close()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package requette
|
||||||
|
|
||||||
|
import (
|
||||||
|
"api_serveurless_go/bd"
|
||||||
|
"api_serveurless_go/types"
|
||||||
|
"database/sql"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetAllTechnologies() types.Technologies {
|
||||||
|
db := bd.GetDB()
|
||||||
|
|
||||||
|
stmt, err := db.Prepare("SELECT * FROM technologie")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
row, err := stmt.Query()
|
||||||
|
defer stmt.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt2, err := db.Prepare("SELECT count(*) FROM technologie")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
row2, err := stmt2.Query()
|
||||||
|
defer stmt2.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
var count int
|
||||||
|
for row2.Next() {
|
||||||
|
err := row2.Scan(&count)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var technologies types.Technologies
|
||||||
|
technologies.Technologies = hydrateTechnologies(row)
|
||||||
|
technologies.Count = count
|
||||||
|
|
||||||
|
return technologies
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func hydrateTechnologies(rows *sql.Rows) []types.TechnologieShort {
|
||||||
|
var technologies []types.TechnologieShort
|
||||||
|
for rows.Next() {
|
||||||
|
var technologie types.TechnologieShort
|
||||||
|
err := rows.Scan(&technologie.Id, &technologie.Name)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
technologies = append(technologies, technologie)
|
||||||
|
}
|
||||||
|
return technologies
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateTechnologie(projet types.TechnologieCreate) *types.TechnologieCreate {
|
||||||
|
db := bd.GetDB()
|
||||||
|
stmt, err := db.Prepare("INSERT INTO technologie (name) VALUES (?)")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = stmt.Exec(projet.Name)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer stmt.Close()
|
||||||
|
return &projet
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateTechnologie(technologie types.TechnologieFull) *types.TechnologieFull {
|
||||||
|
db := bd.GetDB()
|
||||||
|
stmt, err := db.Prepare("UPDATE technologie SET name = ? WHERE id = ?")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = stmt.Exec(technologie.Name, technologie.Id)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer stmt.Close()
|
||||||
|
return &technologie
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteTechnologie(id int) bool {
|
||||||
|
db := bd.GetDB()
|
||||||
|
stmt, err := db.Prepare("DELETE FROM technologie WHERE id = ?")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_, err = stmt.Exec(id)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer stmt.Close()
|
||||||
|
return true
|
||||||
|
}
|
||||||
+122
-62
@@ -1,62 +1,122 @@
|
|||||||
package routes
|
package routes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"api_serveurless_go/requette"
|
"api_serveurless_go/requette"
|
||||||
"encoding/json"
|
"api_serveurless_go/types"
|
||||||
"fmt"
|
"encoding/json"
|
||||||
"net/http"
|
"fmt"
|
||||||
"strconv"
|
"net/http"
|
||||||
"strings"
|
"os"
|
||||||
)
|
"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)
|
|
||||||
}
|
|
||||||
|
// projetsHandler gère la liste des projets
|
||||||
// homeHandler gère la route racine
|
func projetsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
func homeHandler(w http.ResponseWriter, r *http.Request) {
|
w.Header().Set("Access-Control-Allow-Origin", os.Getenv("FRONTEND_URL"))
|
||||||
fmt.Fprintf(w, "Welcome to my website!")
|
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
|
||||||
}
|
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
|
||||||
|
switch r.Method {
|
||||||
// projetsHandler gère la liste des projets
|
case "GET":
|
||||||
func projetsHandler(w http.ResponseWriter, r *http.Request) {
|
w.Header().Set("Content-Type", "application/json")
|
||||||
switch r.Method {
|
w.WriteHeader(http.StatusOK)
|
||||||
case "GET":
|
pageStr := r.URL.Query().Get("page")
|
||||||
w.Header().Set("Content-Type", "application/json")
|
nbStr := r.URL.Query().Get("nb")
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
json.NewEncoder(w).Encode(requette.GetAllProjets())
|
// defaults
|
||||||
case "POST":
|
page := 1
|
||||||
fmt.Fprintf(w, "Créer un nouveau projet")
|
nb := 10
|
||||||
default:
|
|
||||||
http.Error(w, "Méthode non autorisée", http.StatusMethodNotAllowed)
|
if pageStr != "" {
|
||||||
}
|
p, err := strconv.Atoi(pageStr)
|
||||||
}
|
if err != nil {
|
||||||
|
http.Error(w, "Paramètre 'page' invalide", http.StatusBadRequest)
|
||||||
// projetHandler gère les actions sur un projet spécifique
|
return
|
||||||
func projetHandler(w http.ResponseWriter, r *http.Request) {
|
}
|
||||||
id := strings.TrimPrefix(r.URL.Path, "/api/projet/")
|
page = p
|
||||||
if id == "" {
|
}
|
||||||
http.Error(w, "ID manquant", http.StatusBadRequest)
|
|
||||||
return
|
if nbStr != "" {
|
||||||
}
|
n, err := strconv.Atoi(nbStr)
|
||||||
idInt, err := strconv.Atoi(id)
|
if err != nil {
|
||||||
if err != nil {
|
http.Error(w, "Paramètre 'nb' invalide", http.StatusBadRequest)
|
||||||
http.Error(w, "ID invalide", http.StatusBadRequest)
|
return
|
||||||
return
|
}
|
||||||
}
|
nb = n
|
||||||
switch r.Method {
|
}
|
||||||
case "GET":
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
json.NewEncoder(w).Encode(requette.GetAllProjets(nb, page))
|
||||||
w.WriteHeader(http.StatusOK)
|
case "POST":
|
||||||
json.NewEncoder(w).Encode(requette.GetProjetByID(idInt))
|
|
||||||
case "PUT":
|
var projet types.Projetcreate
|
||||||
fmt.Fprintf(w, "Modifier le projet %d", idInt)
|
decoder := json.NewDecoder(r.Body)
|
||||||
case "DELETE":
|
decoder.DisallowUnknownFields()
|
||||||
fmt.Fprintf(w, "Supprimer le projet %d", idInt)
|
err := decoder.Decode(&projet)
|
||||||
default:
|
if err != nil {
|
||||||
http.Error(w, "Méthode non autorisée", http.StatusMethodNotAllowed)
|
http.Error(w, "Erreur de décodage JSON: "+err.Error(), http.StatusBadRequest)
|
||||||
}
|
return
|
||||||
}
|
}
|
||||||
|
fmt.Println(projet.Name, projet.ShortDescription)
|
||||||
|
if requette.CreateProjet(projet) == nil {
|
||||||
|
http.Error(w, "Erreur lors de la création du projet", http.StatusInternalServerError)
|
||||||
|
} else {
|
||||||
|
w.WriteHeader(http.StatusCreated)
|
||||||
|
}
|
||||||
|
case "OPTIONS":
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
return
|
||||||
|
|
||||||
|
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) {
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", os.Getenv("FRONTEND_URL"))
|
||||||
|
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
|
||||||
|
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
|
||||||
|
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":
|
||||||
|
var projet types.ProjetFull
|
||||||
|
decoder := json.NewDecoder(r.Body)
|
||||||
|
decoder.DisallowUnknownFields()
|
||||||
|
err := decoder.Decode(&projet)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Erreur de décodage JSON: "+err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(projet.Name, projet.ShortDescriptionFr)
|
||||||
|
if requette.UpdateProjet(projet) == nil {
|
||||||
|
http.Error(w, "Erreur lors de la mise à jour du projet", http.StatusInternalServerError)
|
||||||
|
} else {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
|
case "DELETE":
|
||||||
|
if requette.DeleteProjet(idInt) {
|
||||||
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
} else {
|
||||||
|
http.Error(w, "Erreur lors de la suppression du projet", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
http.Error(w, "Méthode non autorisée", http.StatusMethodNotAllowed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package routes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetupRoutes() {
|
||||||
|
http.HandleFunc("/api/projets", projetsHandler)
|
||||||
|
http.HandleFunc("/api/projet/", projetHandler)
|
||||||
|
http.HandleFunc("/api/technologies", technologiesHandler)
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package routes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"api_serveurless_go/requette"
|
||||||
|
"api_serveurless_go/types"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// technologiesHandler gère la liste des technologies
|
||||||
|
func technologiesHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", os.Getenv("FRONTEND_URL")) // <-- Remplace avec le port de ton front-end
|
||||||
|
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
|
||||||
|
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
|
||||||
|
switch r.Method {
|
||||||
|
case "GET":
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(requette.GetAllTechnologies())
|
||||||
|
case "POST":
|
||||||
|
|
||||||
|
var technologie types.TechnologieCreate
|
||||||
|
decoder := json.NewDecoder(r.Body)
|
||||||
|
decoder.DisallowUnknownFields()
|
||||||
|
err := decoder.Decode(&technologie)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Erreur de décodage JSON: "+err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if requette.CreateTechnologie(technologie) == nil {
|
||||||
|
http.Error(w, "Erreur lors de la création de la technologie", http.StatusInternalServerError)
|
||||||
|
} else {
|
||||||
|
w.WriteHeader(http.StatusCreated)
|
||||||
|
}
|
||||||
|
case "OPTIONS":
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
return
|
||||||
|
|
||||||
|
default:
|
||||||
|
http.Error(w, "Méthode non autorisée", http.StatusMethodNotAllowed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
type ProjetShort struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
ShortDescriptionFr string `json:"shortdescriptionfr"`
|
||||||
|
Technologies []string `json:"technologies"`
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type Projetcreate struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
ShortDescription string `json:"shortdescriptionfr"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjetFull struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
ShortDescriptionFr string `json:"shortdescriptionfr"`
|
||||||
|
LongDescriptionFr string `json:"longdescriptionfr"`
|
||||||
|
ShortDescriptionEn string `json:"shortdescriptionen"`
|
||||||
|
LongDescriptionEn string `json:"longdescriptionen"`
|
||||||
|
LinkGithub string `json:"linkGithub"`
|
||||||
|
LinkWeb string `json:"linkWeb"`
|
||||||
|
Technologies []string `json:"technologies"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Projets struct {
|
||||||
|
Projets []ProjetShort `json:"projets"`
|
||||||
|
Count int `json:"count"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
type TechnologieShort struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type TechnologieCreate struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TechnologieFull struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Technologies struct {
|
||||||
|
Technologies []TechnologieShort `json:"technologies"`
|
||||||
|
Count int `json:"count"`
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user