Deployer Go sur Supabase : Tutoriel approfondi pour les développeurs intermédiaires
Pourquoi Deployer Go sur Supabase ?
Le développement de back-end est un aspect crucial de la création d'applications modernes, et Go est une excellente option pour ce rôle. Son design concurrentiel, son efficacité en termes de performance et sa simplicité de syntaxe rendent le langage idéal pour de nombreux projets. Supabase, quant à lui, est une plateforme complète pour les applications web et mobiles qui offre une base de données scalable et une API REST/GraphQL. Deploiement Go sur Supabase permet aux développeurs d'exploiter pleinement les avantages de ces deux technologies en créant des back-end performants et scalables.
Un cas concret serait de développer un service backend pour une application mobile ou web nécessitant des opérations complexes sur la base de données. Avec Go et Supabase, vous pouvez concevoir une API robuste capable de traiter des millions de requêtes par jour de manière efficace.
Prerequis
Pour suivre ce tutoriel, vous aurez besoin des éléments suivants :
- Connaissance intermédiaire du langage Go
- Familiarité avec les bases de données et leur manipulation
- Un compte Supabase
- L'environnement de développement Go configuré (Go version 1.17+ recommandée)
Concepts fondamentaux
1. Création d'un projet Go sur Supabase
Pour commencer, vous devez créer un nouveau projet Go et l'intégrer à votre base de données Supabase.
// main.go : Initialisation du projet Go
package main
import (
"fmt"
"log"
"github.com/jackc/pgx/v4/pgxpool"
)
func main() {
// Connexion à la base de données Supabase
conn, err := pgxpool.Connect(context.Background(), "postgres://your-supabase-url")
if err != nil {
log.Fatal(err)
}
defer conn.Close(context.Background())
// Exécution d'une requête SQL
rows, err := conn.Query(context.Background(), "SELECT * FROM your_table")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int
var name string
err = rows.Scan(&id, &name)
if err != nil {
log.Fatal(err)
}
fmt.Printf("ID: %d, Name: %s\n", id, name)
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
}
2. Utilisation des packages de Go
Go dispose d'une grande collection de packages officiels et tiers qui facilitent le développement de projets complexes.
// go.mod : Gestion des dépendances Go
module github.com/yourusername/supabase-go-example
go 1.17
require (
github.com/jackc/pgx/v4 v4.20.3
)
3. Création d'une API REST avec Go
Pour créer une API REST, vous pouvez utiliser le package net/http.
// main.go : Création d'une simple API REST
package main
import (
"fmt"
"log"
"net/http"
)
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, world!")
}
func main() {
http.HandleFunc("/hello", helloHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
4. Manipulation de la base de données avec Go et Supabase
Utilisez le package pgx pour interagir avec votre base de données.
// main.go : Opérations CRUD sur une table
package main
import (
"context"
"fmt"
"log"
"github.com/jackc/pgx/v4/pgxpool"
)
func main() {
conn, err := pgxpool.Connect(context.Background(), "postgres://your-supabase-url")
if err != nil {
log.Fatal(err)
}
defer conn.Close(context.Background())
// Insertion
_, err = conn.Exec(context.Background(), `INSERT INTO your_table (name) VALUES ($1)`, "New Item")
if err != nil {
log.Fatal(err)
}
// Lecture
rows, err := conn.Query(context.Background(), `SELECT * FROM your_table`)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int
var name string
err = rows.Scan(&id, &name)
if err != nil {
log.Fatal(err)
}
fmt.Printf("ID: %d, Name: %s\n", id, name)
}
// Mise à jour
_, err = conn.Exec(context.Background(), `UPDATE your_table SET name=$1 WHERE id=$2`, "Updated Item", 1)
if err != nil {
log.Fatal(err)
}
// Suppression
_, err = conn.Exec(context.Background(), `DELETE FROM your_table WHERE id=$1`, 1)
if err != nil {
log.Fatal(err)
}
}
Mise en pratique : projet fil rouge
Création d'un gestionnaire de tâches
Étape 1 : Initialisation du projet
Créer un nouveau fichier main.go et ajouter les dépendances nécessaires.
// main.go : Initialisation du projet Go
package main
import (
"fmt"
"log"
"github.com/jackc/pgx/v4/pgxpool"
)
func main() {
conn, err := pgxpool.Connect(context.Background(), "postgres://your-supabase-url")
if err != nil {
log.Fatal(err)
}
defer conn.Close(context.Background())
// Exécution d'une requête SQL
rows, err := conn.Query(context.Background(), "SELECT * FROM tasks")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int
var name string
var completed bool
err = rows.Scan(&id, &name, &completed)
if err != nil {
log.Fatal(err)
}
fmt.Printf("ID: %d, Name: %s, Completed: %t\n", id, name, completed)
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
}
Étape 2 : Création de l'API REST
Ajoutez un fichier routes.go pour définir les routes de votre API.
// routes.go : Définition des routes de l'API
package main
import (
"github.com/gin-gonic/gin"
)
func setupRoutes(router *gin.Engine) {
router.GET("/tasks", getTasks)
router.POST("/tasks", createTask)
router.PUT("/tasks/:id", updateTask)
router.DELETE("/tasks/:id", deleteTask)
}
func main() {
router := gin.Default()
setupRoutes(router)
router.Run(":8080")
}
Étape 3 : Implémentation des fonctions de l'API
Ajoutez le fichier handlers.go pour implémenter les fonctionnalités de l'API.
// handlers.go : Implémentation des fonctions de l'API
package main
import (
"context"
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"github.com/jackc/pgx/v4/pgxpool"
)
func getTasks(c *gin.Context) {
conn, err := pgxpool.Connect(context.Background(), "postgres://your-supabase-url")
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
defer conn.Close(context.Background())
rows, err := conn.Query(context.Background(), `SELECT * FROM tasks`)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
defer rows.Close()
var tasks []Task
for rows.Next() {
var task Task
err = rows.Scan(&task.ID, &task.Name, &task.Completed)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
tasks = append(tasks, task)
}
err = rows.Err()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, tasks)
}
func createTask(c *gin.Context) {
var input struct {
Name string `json:"name" binding:"required"`
}
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
conn, err := pgxpool.Connect(context.Background(), "postgres://your-supabase-url")
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
defer conn.Close(context.Background())
_, err = conn.Exec(context.Background(), `INSERT INTO tasks (name) VALUES ($1)`, input.Name)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusCreated, gin.H{"message": "Task created successfully"})
}
func updateTask(c *gin.Context) {
var input struct {
Name string `json:"name"`
Completed bool `json:"completed"`
}
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
id := c.Param("id")
conn, err := pgxpool.Connect(context.Background(), "postgres://your-supabase-url")
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
defer conn.Close(context.Background())
_, err = conn.Exec(context.Background(), `UPDATE tasks SET name=$1, completed=$2 WHERE id=$3`, input.Name, input.Completed, id)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "Task updated successfully"})
}
func deleteTask(c *gin.Context) {
id := c.Param("id")
conn, err := pgxpool.Connect(context.Background(), "postgres://your-supabase-url")
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
defer conn.Close(context.Background())
_, err = conn.Exec(context.Background(), `DELETE FROM tasks WHERE id=$1`, id)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "Task deleted successfully"})
}
Erreurs frequentes et debugging
1. Connexion à la base de données échoue
## ❌ Mauvais
conn, err := pgxpool.Connect(context.Background(), "postgres://your-supabase-url")
if err != nil {
log.Fatal(err)
}
## ✅ Correct
dbURL := fmt.Sprintf("postgres://%s:%s@%s:%d/%s", "username", "password", "host", 5432, "dbname")
conn, err := pgxpool.Connect(context.Background(), dbURL)
if err != nil {
log.Fatal(err)
}
2. Erreur de syntaxe dans la requête SQL
## ❌ Mauvais
rows, err := conn.Query(context.Background(), `SELECT * FROM your_table WHERE id = $1`, "invalid-id")
## ✅ Correct
id := 1
rows, err := conn.Query(context.Background(), `SELECT * FROM your_table WHERE id = $1`, id)
3. Erreur de type lors de la lecture des données
## ❌ Mauvais
var name string
err = rows.Scan(&name)
## ✅ Correct
var name string
err = rows.Scan(&name, &completed)
Pour aller plus loin
- Développement asynchrone avec Go : Apprenez à utiliser les goroutines et les channels pour un développement concurrent.
- Tests unitaires en Go : Ajoutez des tests unitaires à votre projet pour vous assurer que tout fonctionne comme prévu.
- Gestion de l'authentification avec Supabase : Intégrez l'authentification dans votre application pour une sécurité accrue.
Défi pratique
Créez une API REST pour un blog simple, permettant d'afficher, ajouter, mettre à jour et supprimer des articles. Utilisez le package github.com/gin-gonic/gin pour la création de l'API et pgx pour interagir avec votre base de données Supabase.