First commit for realz API REST service
This commit is contained in:
9
config.prod.yaml
Normal file
9
config.prod.yaml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
server:
|
||||||
|
address: "127.0.0.1:8080" # Plus sécurisé, n'écoute que sur l'interface locale
|
||||||
|
|
||||||
|
database:
|
||||||
|
host: "prod-db.example.com"
|
||||||
|
user: "prod_user"
|
||||||
|
password: "a_very_secret_password" # Idéalement, à gérer via un secret manager
|
||||||
|
port: 5432
|
||||||
|
sslmode: "require"
|
10
config.yaml
Normal file
10
config.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
server:
|
||||||
|
address: "0.0.0.0:8080"
|
||||||
|
|
||||||
|
database:
|
||||||
|
user: "realz"
|
||||||
|
password: "realz"
|
||||||
|
dbname: "realz"
|
||||||
|
host: "localhost"
|
||||||
|
port: 5433
|
||||||
|
sslmode: "disable"
|
@@ -1,4 +1,13 @@
|
|||||||
services:
|
services:
|
||||||
|
api:
|
||||||
|
image: postgrest/postgrest
|
||||||
|
ports:
|
||||||
|
- "3300:3000"
|
||||||
|
environment:
|
||||||
|
PGRST_DB_URI: postgres://${PGRST_AUTHUSER}:${PGRST_PASSWORD}@postgis:5432
|
||||||
|
PGRST_DB_SCHEMAS: raf20lambert93
|
||||||
|
PGRST_DB_ANON_ROLE: web_anon
|
||||||
|
PGRST_OPENAPI_SERVER_PROXY_URI: http://127.0.0.1:3000
|
||||||
postgis:
|
postgis:
|
||||||
image: realz
|
image: realz
|
||||||
container_name: postgis_initialized
|
container_name: postgis_initialized
|
||||||
@@ -6,6 +15,8 @@ services:
|
|||||||
- POSTGRES_USER=${POSTGRES_USER}
|
- POSTGRES_USER=${POSTGRES_USER}
|
||||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||||
- POSTGRES_DB=${POSTGRES_DB} # Base de données pour l'administration, pas celle de l'app
|
- POSTGRES_DB=${POSTGRES_DB} # Base de données pour l'administration, pas celle de l'app
|
||||||
|
- PGRST_AUTHUSER=${PGRST_AUTHUSER}
|
||||||
|
- PGRST_PASSWORD=${PGRST_PASSWORD}
|
||||||
ports:
|
ports:
|
||||||
- "5433:5432"
|
- "5433:5432"
|
||||||
volumes:
|
volumes:
|
||||||
|
@@ -11,5 +11,14 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E
|
|||||||
EOSQL
|
EOSQL
|
||||||
|
|
||||||
echo "Init database data with RGF93"
|
echo "Init database data with RGF93"
|
||||||
raster2pgsql -s RGF93 -I -C -M /opt/RAF20_lambert93.tiff -F -t 100x100 public.raf20lamber93 | psql -U ${POSTGRES_USER} -d ${POSTGRES_DB}
|
raster2pgsql -s EPSG:2154 -I -C -M /opt/RAF20_lambert93.tiff -F -t 100x100 public.raf20lambert93 | psql -U ${POSTGRES_USER} -d ${POSTGRES_DB}
|
||||||
exit $?
|
exit $?
|
||||||
|
|
||||||
|
echo "Create postgrest roles"
|
||||||
|
|
||||||
|
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
||||||
|
CREATE ROLE webanon nologin;
|
||||||
|
GRANT USAGE ON SCHEMA raf20lamber93 TO webanon;
|
||||||
|
GRANT SELECT ON SCHEMA raf20lamber93 TO webanon;
|
||||||
|
GRANT web_anon to ${POSTGRES_USER}
|
||||||
|
EOSQL
|
||||||
|
171
index.html
Normal file
171
index.html
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>API getRealZ</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; margin: 2em; background-color: #f4f4f9; color: #333; display: flex; flex-direction: column; align-items: center; }
|
||||||
|
h1 { color: #333; }
|
||||||
|
.container { max-width: 500px; width: 100%; }
|
||||||
|
form { background: rgb(255, 255, 255); padding: 2em; border-radius: 0 8px 8px 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
|
||||||
|
.form-group { margin-bottom: 1em; }
|
||||||
|
.form-row { display: flex; gap: 1em; }
|
||||||
|
.form-row .form-group { flex: 1; }
|
||||||
|
label { display: block; margin-bottom: 0.5em; font-weight: bold; }
|
||||||
|
input, select { width: 100%; padding: 0.8em; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px; background-color: white; font-size: 1em; }
|
||||||
|
button { padding: 0.7em 1.5em; border: none; background-color: #007bff; color: white; border-radius: 4px; cursor: pointer; font-size: 1em; }
|
||||||
|
button:hover { background-color: #0056b3; }
|
||||||
|
button:disabled { background-color: #aaa; cursor: not-allowed; }
|
||||||
|
#result { margin-top: 1em; padding: 1em; background: #e9ecef; border-radius: 4px; text-align: center; word-wrap: break-word; }
|
||||||
|
.tabs { display: flex; }
|
||||||
|
.tabs button {
|
||||||
|
flex: 1; padding: 1em; border: 1px solid #ccc; border-bottom: none;
|
||||||
|
background-color: #f4f4f9; cursor: pointer; border-radius: 8px 8px 0 0;
|
||||||
|
color: black;
|
||||||
|
margin-bottom: -1px; font-size: 1em;
|
||||||
|
}
|
||||||
|
.tabs button.active {
|
||||||
|
background-color: white; border-bottom: 1px solid white; font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<h1>Test de l'API Altitude</h1>
|
||||||
|
|
||||||
|
<div class="tabs">
|
||||||
|
<button id="tab-getCorrection" class="active">Obtenir la Correction Orthométrique (N)</button>
|
||||||
|
<button id="tab-getCorrectedZ">Calculer l'Altitude Corrigée (H)</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form id="coordForm">
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="lat">Latitude :</label>
|
||||||
|
<input type="number" id="lat" name="lat" step="any" required value="47.2184">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="lon">Longitude :</label>
|
||||||
|
<input type="number" id="lon" name="lon" step="any" required value="-1.5536">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" id="z-group" style="display: none;">
|
||||||
|
<label for="z">Altitude mesurée (ellipsoïdale h) :</label>
|
||||||
|
<input type="number" id="z" name="z" step="any" value="250.0" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="srcProj">Projection Source (SRID) :</label>
|
||||||
|
<select id="srcProj" name="srcProj" required>
|
||||||
|
<option value="4326" selected>WGS 84 (GPS)</option>
|
||||||
|
<option value="2154">RGF93 / Lambert-93 (France)</option>
|
||||||
|
<option value="3857">WGS 84 / Pseudo-Mercator (Web)</option>
|
||||||
|
<option value="4258">ETRS89 (Europe)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="dstProj">Projection Destination (SRID) :</label>
|
||||||
|
<select id="dstProj" name="dstProj" required>
|
||||||
|
<option value="2154" selected>RGF93 / Lambert-93 (France)</option>
|
||||||
|
<option value="4326">WGS 84 (GPS)</option>
|
||||||
|
<option value="3857">WGS 84 / Pseudo-Mercator (Web)</option>
|
||||||
|
<option value="4258">ETRS89 (Europe)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<button type="submit" id="submit-btn">Obtenir la correction</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div id="result">
|
||||||
|
Entrez des coordonnées et cliquez sur le bouton.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const form = document.getElementById('coordForm');
|
||||||
|
const resultDiv = document.getElementById('result');
|
||||||
|
const zGroup = document.getElementById('z-group');
|
||||||
|
const zInput = document.getElementById('z');
|
||||||
|
const submitBtn = document.getElementById('submit-btn');
|
||||||
|
const tabGetCorrection = document.getElementById('tab-getCorrection');
|
||||||
|
const tabGetCorrectedZ = document.getElementById('tab-getCorrectedZ');
|
||||||
|
|
||||||
|
let mode = 'getCorrection'; // 'getCorrection' ou 'getCorrectedZ'
|
||||||
|
|
||||||
|
function setMode(newMode) {
|
||||||
|
mode = newMode;
|
||||||
|
if (mode === 'getCorrection') {
|
||||||
|
zGroup.style.display = 'none';
|
||||||
|
zInput.required = false;
|
||||||
|
submitBtn.textContent = "Obtenir la correction (N)";
|
||||||
|
tabGetCorrection.classList.add('active');
|
||||||
|
tabGetCorrectedZ.classList.remove('active');
|
||||||
|
} else { // 'getCorrectedZ'
|
||||||
|
zGroup.style.display = 'block';
|
||||||
|
zInput.required = true;
|
||||||
|
submitBtn.textContent = "Calculer l'altitude corrigée (H)";
|
||||||
|
tabGetCorrection.classList.remove('active');
|
||||||
|
tabGetCorrectedZ.classList.add('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tabGetCorrection.addEventListener('click', () => setMode('getCorrection'));
|
||||||
|
tabGetCorrectedZ.addEventListener('click', () => setMode('getCorrectedZ'));
|
||||||
|
|
||||||
|
form.addEventListener('submit', async function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
submitBtn.disabled = true;
|
||||||
|
resultDiv.textContent = 'Chargement...';
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
lat: parseFloat(document.getElementById('lat').value),
|
||||||
|
lon: parseFloat(document.getElementById('lon').value),
|
||||||
|
srcProj: parseInt(document.getElementById('srcProj').value, 10),
|
||||||
|
dstProj: parseInt(document.getElementById('dstProj').value, 10)
|
||||||
|
};
|
||||||
|
|
||||||
|
let endpoint = '/getorthocorrec';
|
||||||
|
|
||||||
|
if (mode === 'getCorrectedZ') {
|
||||||
|
endpoint = '/getcorrectedaltitude';
|
||||||
|
body.z = parseFloat(zInput.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(endpoint, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
if (mode === 'getCorrection') {
|
||||||
|
resultDiv.textContent = `Correction orthométrique (N) : - ${data.z.toFixed(8)} mètres`;
|
||||||
|
} else {
|
||||||
|
resultDiv.textContent = `Altitude corrigée (H) : ${data.corrected_z.toFixed(8)} mètres`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resultDiv.textContent = `Erreur : ${data.error}`;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
resultDiv.textContent = `Erreur de communication avec l'API : ${error.message}`;
|
||||||
|
} finally {
|
||||||
|
submitBtn.disabled = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialiser le mode au chargement
|
||||||
|
setMode('getCorrection');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
202
main.go
Normal file
202
main.go
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
_ "github.com/lib/pq" // Driver PostgreSQL
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config struct to hold all configuration for our application
|
||||||
|
type Config struct {
|
||||||
|
Database struct {
|
||||||
|
User string `mapstructure:"user"`
|
||||||
|
Password string `mapstructure:"password"`
|
||||||
|
Dbname string `mapstructure:"dbname"`
|
||||||
|
Host string `mapstructure:"host"`
|
||||||
|
Port int `mapstructure:"port"`
|
||||||
|
Sslmode string `mapstructure:"sslmode"`
|
||||||
|
} `mapstructure:"database"`
|
||||||
|
Server struct {
|
||||||
|
Address string `mapstructure:"address"`
|
||||||
|
} `mapstructure:"server"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GpsCoord représente les coordonnées GPS reçues en entrée.
|
||||||
|
// Les noms de champs commencent par une majuscule pour être exportables
|
||||||
|
// et donc accessibles par le décodeur JSON de Gin.
|
||||||
|
type GpsCoord struct {
|
||||||
|
Lat float64 `json:"lat" binding:"required"`
|
||||||
|
Lon float64 `json:"lon" binding:"required"`
|
||||||
|
SrcProj int `json:"srcProj" binding:"required"`
|
||||||
|
DstProj int `json:"dstProj" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GpsCoordWithZ représente les coordonnées GPS et l'altitude reçues pour le calcul de différence.
|
||||||
|
type GpsCoordWithZ struct {
|
||||||
|
Lat float64 `json:"lat" binding:"required"`
|
||||||
|
Lon float64 `json:"lon" binding:"required"`
|
||||||
|
Z float64 `json:"z" binding:"required"`
|
||||||
|
SrcProj int `json:"srcProj" binding:"required"`
|
||||||
|
DstProj int `json:"dstProj" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AltitudeResponse représente la réponse JSON retournée par l'API.
|
||||||
|
type AltitudeResponse struct {
|
||||||
|
Z float64 `json:"z"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CorrectedAltitudeResponse représente la réponse JSON pour l'altitude corrigée.
|
||||||
|
type CorrectedAltitudeResponse struct {
|
||||||
|
CorrectedZ float64 `json:"corrected_z"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// queryAltitude interroge la base de données pour obtenir l'altitude réelle pour des coordonnées données.
|
||||||
|
// C'est une fonction utilitaire pour éviter la duplication de code.
|
||||||
|
func queryOrthometricCorrection(db *sql.DB, lat, lon float64, srcProj, dstProj int) (float64, error) {
|
||||||
|
var altitude float64
|
||||||
|
|
||||||
|
query := `
|
||||||
|
SELECT ST_Value(rast, ST_Transform(ST_SetSRID(ST_MakePoint($2, $1), $3::integer), $4::integer)) AS pixel_value
|
||||||
|
FROM raf20lamber93
|
||||||
|
WHERE ST_Intersects(rast, ST_Transform(ST_SetSRID(ST_MakePoint($2, $1), $3::integer), $4::integer));
|
||||||
|
`
|
||||||
|
|
||||||
|
// On exécute la requête. QueryRow est idéal car nous attendons au plus une ligne.
|
||||||
|
err := db.QueryRow(query, lat, lon, srcProj, dstProj).Scan(&altitude)
|
||||||
|
if err != nil {
|
||||||
|
// Si aucune ligne n'est trouvée, ST_Value renvoie NULL, ce qui cause une erreur au Scan.
|
||||||
|
// On retourne l'erreur pour qu'elle soit gérée par la fonction appelante.
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return altitude, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getRealZ est le handler pour notre route. Il prend une connexion à la BDD en paramètre.
|
||||||
|
func getOrthometricCorrection(db *sql.DB) gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
var input GpsCoord
|
||||||
|
|
||||||
|
// On valide et on lie le JSON d'entrée à notre struct GpsCoord.
|
||||||
|
if err := c.ShouldBindJSON(&input); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Paramètres invalides: " + err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// On appelle notre fonction utilitaire pour obtenir l'altitude.
|
||||||
|
altitude, err := queryOrthometricCorrection(db, input.Lat, input.Lon, input.SrcProj, input.DstProj)
|
||||||
|
if err != nil {
|
||||||
|
// Si aucune ligne n'est trouvée, ST_Value renvoie NULL, ce qui cause une erreur au Scan.
|
||||||
|
// On peut considérer cette erreur comme un "non trouvé".
|
||||||
|
// Pour une gestion plus fine, il faudrait vérifier le type d'erreur exact.
|
||||||
|
log.Printf("Erreur de la base de données ou aucune valeur trouvée: %v", err)
|
||||||
|
c.JSON(http.StatusNotFound, gin.H{"error": "Aucune donnée d'altitude trouvée pour ces coordonnées."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.IndentedJSON(http.StatusOK, AltitudeResponse{Z: altitude})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCorrectedAltitude est le handler pour la nouvelle route.
|
||||||
|
// Il prend une altitude mesurée et retourne l'altitude corrigée.
|
||||||
|
func getCorrectedAltitude(db *sql.DB) gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
var input GpsCoordWithZ
|
||||||
|
|
||||||
|
// On valide et on lie le JSON d'entrée à notre struct GpsCoordWithZ.
|
||||||
|
if err := c.ShouldBindJSON(&input); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Paramètres invalides: " + err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// On appelle notre fonction utilitaire pour obtenir la correction orthométrique (N).
|
||||||
|
correction, err := queryOrthometricCorrection(db, input.Lat, input.Lon, input.SrcProj, input.DstProj)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Erreur de la base de données ou aucune valeur trouvée: %v", err)
|
||||||
|
c.JSON(http.StatusNotFound, gin.H{"error": "Aucune donnée de correction trouvée pour ces coordonnées."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// On calcule l'altitude corrigée (H = h - N).
|
||||||
|
// input.Z est l'altitude ellipsoïdale (h).
|
||||||
|
// correction est l'ondulation du géoïde (N).
|
||||||
|
correctedAltitude := input.Z - correction
|
||||||
|
c.IndentedJSON(http.StatusOK, CorrectedAltitudeResponse{CorrectedZ: correctedAltitude})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// --- Chargement de la configuration ---
|
||||||
|
// 0. Configuration pour les variables d'environnement
|
||||||
|
viper.SetEnvPrefix("APP") // Les variables devront commencer par "APP_" (ex: APP_SERVER_ADDRESS)
|
||||||
|
|
||||||
|
// 1. Fichier de configuration de base
|
||||||
|
viper.SetConfigName("config") // config.yaml
|
||||||
|
viper.SetConfigType("yaml")
|
||||||
|
viper.AddConfigPath(".")
|
||||||
|
|
||||||
|
// Lecture du fichier de base. On ne s'arrête pas s'il n'est pas trouvé.
|
||||||
|
if err := viper.ReadInConfig(); err != nil {
|
||||||
|
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
|
||||||
|
log.Fatalf("Erreur lors de la lecture du fichier de base config.yaml: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Surcharge par environnement (via la variable APP_ENV)
|
||||||
|
if env := os.Getenv("APP_ENV"); env != "" {
|
||||||
|
viper.SetConfigName("config." + env) // ex: config.prod.yaml
|
||||||
|
// MergeInConfig fusionne la nouvelle configuration avec celle déjà chargée.
|
||||||
|
// Les valeurs du nouveau fichier écrasent les anciennes.
|
||||||
|
if err := viper.MergeInConfig(); err != nil {
|
||||||
|
log.Printf("Avertissement : impossible de charger le fichier de configuration pour l'environnement '%s': %v", env, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2a. Indiquer à Viper de lire les variables d'environnement APRÈS avoir lu les fichiers.
|
||||||
|
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) // Remplace les "." par des "_" (ex: server.address -> SERVER_ADDRESS)
|
||||||
|
viper.AutomaticEnv()
|
||||||
|
|
||||||
|
// 3. "Unmarshal" de la configuration finale dans la struct
|
||||||
|
var config Config
|
||||||
|
if err := viper.Unmarshal(&config); err != nil {
|
||||||
|
log.Fatalf("Impossible de décoder la configuration dans la structure : %v", err)
|
||||||
|
}
|
||||||
|
// --- Fin du chargement de la configuration ---
|
||||||
|
|
||||||
|
// Chaîne de connexion à votre base de données PostgreSQL.
|
||||||
|
// Construite à partir de la configuration.
|
||||||
|
connStr := fmt.Sprintf("user=%s password=%s dbname=%s host=%s port=%d sslmode=%s",
|
||||||
|
config.Database.User, config.Database.Password, config.Database.Dbname,
|
||||||
|
config.Database.Host, config.Database.Port, config.Database.Sslmode,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Connexion à la base de données
|
||||||
|
db, err := sql.Open("postgres", connStr)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Impossible de se connecter à la base de données:", err)
|
||||||
|
} else {
|
||||||
|
log.Println("Connecté à la base de données PostgreSQL")
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
router := gin.Default()
|
||||||
|
|
||||||
|
// Servir les fichiers statiques (index.html, etc.) depuis le répertoire courant.
|
||||||
|
router.StaticFS("/", http.Dir("."))
|
||||||
|
|
||||||
|
// La route est maintenant un POST pour recevoir un corps de requête JSON.
|
||||||
|
router.POST("/getorthocorrec", getOrthometricCorrection(db))
|
||||||
|
|
||||||
|
// Nouvelle route pour obtenir l'altitude corrigée.
|
||||||
|
router.POST("/getcorrectedaltitude", getCorrectedAltitude(db))
|
||||||
|
|
||||||
|
log.Printf("Démarrage du serveur sur %s", config.Server.Address)
|
||||||
|
router.Run(config.Server.Address)
|
||||||
|
}
|
Reference in New Issue
Block a user