SDK Go et JavaScript PocketBase : Manipulation avancée des données 2026
Introduction
Dans PocketBase, l'API REST couvre la plupart des besoins quotidiens pour interagir avec vos données. Mais pour des cas plus complexes, comme des hooks personnalisés ou une logique métier avancée, les SDK Go et JavaScript côté serveur entrent en jeu. Ces SDK permettent un accès direct à la base de données SQLite, sans passer par les endpoints HTTP. Vous pouvez exécuter des requêtes SQL brutes, gérer des transactions atomiques, ou manipuler des collections et records de manière programmatique.
Ces outils sont particulièrement utiles pour les startups et PME qui construisent des applications scalables sans équipe backend dédiée. Go offre des performances natives pour des projets gourmands, tandis que JavaScript permet un prototypage rapide sans compilation. Dans cet article, nous explorons l'accès programmatique depuis Go et JS, les méthodes clés comme dao.FindRecordsByFilter(), les transactions, les requêtes SQL, et une comparaison des deux langages. Tout est expliqué pour les débutants, avec des exemples concrets tirés de la documentation officielle.
Accès programmatique depuis Go et JavaScript
Pour utiliser ces SDK, vous devez étendre PocketBase via des hooks ou une application personnalisée. En Go, cela se fait en important le package github.com/pocketbase/pocketbase/core. En JavaScript, c'est via le dossier pb_hooks et la machine virtuelle JSVM.
En Go : Configuration de base
Commencez par créer une application PocketBase personnalisée. Voici un exemple minimal pour accéder à la base de données :
package main
import (
"log"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/core"
)
func main() {
app := pocketbase.New()
// Hook pour accéder à la DB avant le démarrage
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
// Exemple : Accès à une collection
collection, err := app.FindCollectionByNameOrId("users")
if err != nil {
log.Printf("Erreur : %v", err)
return err
}
log.Printf("Collection trouvée : %s", collection.Name)
return nil
})
if err := app.Start(); err != nil {
log.Fatal(err)
}
}
Ici, app est l'instance centrale. app.DB() donne accès au builder de requêtes dbx.Builder pour des opérations SQL. Pour les collections et records, utilisez app.FindCollectionByNameOrId() ou app.FindRecordById().
En JavaScript : Via les hooks JSVM
En JS, placez vos scripts dans pb_hooks/. Les globals comme $app et $db sont disponibles. Exemple de hook pour accéder à une collection :
// pb_hooks/onBeforeServe.js
let collection = $app.findCollectionByNameOrId("users");
if (collection) {
console.log("Collection trouvée : " + collection.name);
}
$app est l'équivalent de app en Go. $app.db() retourne le builder pour SQL. Ces accès sont sécurisés et intègrent les règles d'authentification de PocketBase.
Pour un débutant, commencez par Go si votre projet est en backend pur ; JS si vous préférez la flexibilité sans rebuild.
Gestion des collections avec les SDK
Les collections sont les "tables" de PocketBase. Les SDK permettent de les créer, lire, mettre à jour et supprimer (CRUD) programmatiquement, souvent lors de migrations.
En Go : Opérations sur les collections
Utilisez core.App pour les méthodes principales. Importez github.com/pocketbase/pocketbase/core et github.com/pocketbase/dbx.
- Récupérer une collection :
app.FindCollectionByNameOrId("nom")retourne*core.Collectionounilavec erreur si non trouvée.
Exemple :
collection, err := app.FindCollectionByNameOrId("users")
if err != nil {
log.Fatal(err)
}
fmt.Println(collection.Name) // "users"
- Récupérer plusieurs collections :
app.FindAllCollections(types...)filtre par type (e.g., "auth", "view").
Exemple :
collections, err := app.FindAllCollections(core.CollectionTypeAuth)
- Requête custom :
app.CollectionQuery()pour un builder SELECT.
Exemple :
import "github.com/pocketbase/dbx"
collections := []*core.Collection{}
err := app.CollectionQuery().
AndWhere(dbx.HashExp{"system": true}).
OrderBy("created DESC").
All(&collections)
- Créer une collection : Utilisez
core.NewBaseCollection("nom"), ajoutez champs et règles, puisapp.Save(collection).
Exemple complet :
import (
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/types"
)
collection := core.NewBaseCollection("articles")
collection.ViewRule = types.Pointer("@request.auth.id != ''")
collection.Fields.Add(&core.TextField{Name: "title", Required: true})
collection.Fields.Add(&core.RelationField{Name: "user", Required: true, CollectionId: usersCollection.Id})
err := app.Save(collection)
- Mettre à jour : Chargez, modifiez, sauvegardez.
Exemple :
collection, _ = app.FindCollectionByNameOrId("articles")
collection.DeleteRule = types.Pointer("@request.auth.id != ''")
collection.Fields.Add(&core.EditorField{Name: "description"})
app.Save(collection)
- Supprimer :
app.Delete(collection).
Note : Utilisez app.SaveNoValidate() pour sauter la validation.
En JavaScript : Opérations sur les collections
Similaire, mais avec des classes JS. $app expose les méthodes.
- Récupérer une collection :
$app.findCollectionByNameOrId("nom")jette une erreur si non trouvée.
Exemple :
let collection = $app.findCollectionByNameOrId("users");
console.log(collection.name);
- Récupérer plusieurs :
$app.findAllCollections(...types).
Exemple :
let authCollections = $app.findAllCollections("auth");
- Requête custom :
$app.collectionQuery().
Exemple :
let collections = arrayOf(new Collection);
$app.collectionQuery()
.andWhere($dbx.hashExp({ "viewRule": null }))
.orderBy("created DESC")
.all(collections);
- Créer :
new Collection({ ... }), puis$app.save(collection).
Exemple :
let collection = new Collection({
type: "base",
name: "articles",
viewRule: "@request.auth.id != ''",
fields: [
{ name: "title", type: "text", required: true, max: 10 },
{ name: "user", type: "relation", required: true, collectionId: "users_id" }
]
});
$app.save(collection);
- Mettre à jour et supprimer : Analogues à Go.
Ces opérations sont idéales pour automatiser la création de schémas lors du bootstrap d'une app startup.
Gestion des records avec les SDK
Les records sont les lignes de vos collections. Les SDK offrent des getters/setters typés et des requêtes filtrées.
En Go : Opérations sur les records
Importez core. Les méthodes sont sur app et *core.Record.
- Récupérer un record :
app.FindRecordById(collection, id)ouapp.FindFirstRecordByFilter(collection, filter, params).
Exemple pour FindRecordsByFilter (équivalent à dao.FindRecordsByFilter) :
records, err := app.FindRecordsByFilter(
"articles",
"status = 'public' && category = {:category}",
"-published", // tri
10, 0, // limit, offset
dbx.Params{"category": "news"},
)
- Set/Get :
record.Set("champ", valeur);record.GetString("champ").
Exemple :
record.Set("title", "Mon article")
title := record.GetString("title")
- Créer :
core.NewRecord(collection), set champs,app.Save(record).
Exemple avec fichiers :
import "github.com/pocketbase/pocketbase/tools/filesystem"
record := core.NewRecord(collection)
record.Set("title", "Article")
f1, _ := filesystem.NewFileFromPath("/path/file.txt")
record.Set("files", []*filesystem.File{f1})
app.Save(record)
- Mettre à jour : Chargez, set, save. Pour append/supprimer :
record.Set("files+", [...])ourecord.Set("files-", ["nom"]). - Supprimer :
app.Delete(record). - Expansion de relations :
app.ExpandRecord(record, []string{"relation"}).
En JavaScript : Opérations sur les records
Similaire, avec Record class.
- Récupérer :
$app.findRecordById("collection", "id")ou$app.findRecordsByFilter(...).
Exemple :
let records = $app.findRecordsByFilter(
"articles",
"status = 'public' && category = {:category}",
"-published",
10,
0,
{ category: "news" }
);
- Set/Get :
record.set("champ", valeur);record.getString("champ"). - Créer/Mettre à jour/Supprimer : Analogues, avec
$app.save(record)et modificateurs comme"files+".
Exemple création :
let record = new Record(collection);
record.set("title", "Article");
let f1 = $filesystem.fileFromPath("/path/file.txt");
record.set("files", [f1]);
$app.save(record);
Pour les PME, ces méthodes simplifient l'ajout de logique comme l'auto-génération de slugs (record.Set("slug:autogenerate", "prefix-")).
Transactions
Les transactions assurent l'atomicité : tout réussit ou rien. Utiles pour des opérations multiples, comme créer un user et un post lié.
En Go
app.RunInTransaction(func(txApp core.App) error { ... }). Utilisez txApp à l'intérieur.
Exemple :
err := app.RunInTransaction(func(txApp core.App) error {
record, _ := txApp.FindRecordById("users", "id")
record.Set("status", "active")
txApp.Save(record)
// Raw delete
_, err := txApp.DB().NewQuery("DELETE FROM drafts WHERE user = {:id}").Bind(dbx.Params{"id": "id"}).Execute()
return err
})
if err != nil {
log.Fatal(err)
}
Évitez les tâches longues (e-mails) dedans pour ne pas bloquer la DB.
En JavaScript
$app.runInTransaction((txApp) => { ... }).
Exemple :
$app.runInTransaction((txApp) => {
let record = txApp.findRecordById("users", "id");
record.set("status", "active");
txApp.save(record);
txApp.db().newQuery("DELETE FROM drafts WHERE user = {:id}")
.bind({ id: "id" })
.execute();
});
Les transactions supportent l'imbrication, mais gardez-les courtes pour les startups à fort trafic.
Requêtes SQL brutes
Quand les helpers ne suffisent pas, utilisez le builder dbx pour du SQL pur, avec protection contre les injections via params.
En Go
app.DB() retourne dbx.Builder.
Exemple simple SELECT :
type User struct {
Id string `db:"id"`
Email string `db:"email"`
}
user := User{}
err := app.DB().NewQuery("SELECT id, email FROM users WHERE id = {:id}").
Bind(dbx.Params{"id": "123"}).
One(&user)
Builder pour jointures :
users := []User{}
app.DB().
Select("users.id", "users.email").
From("users").
LeftJoin("profiles", dbx.NewExp("profiles.user_id = users.id")).
Where(dbx.HashExp{"users.status": "active"}).
Limit(10).
All(&users)
Expressions : dbx.HashExp{"status": true} génère status = true. dbx.Like("name", "john") pour %john%.
En JavaScript
$app.db().
Exemple :
const user = new DynamicModel({ id: "", email: "" });
$app.db()
.newQuery("SELECT id, email FROM users WHERE id = {:id}")
.bind({ id: "123" })
.one(user);
console.log(user.email);
Builder :
const users = arrayOf(new DynamicModel({ id: "", email: "" }));
$app.db()
.select("users.id", "users.email")
.from("users")
.leftJoin("profiles", $dbx.exp("profiles.user_id = users.id"))
.where($dbx.hashExp({ status: "active" }))
.limit(10)
.all(users);
Pour les débutants, commencez par hashExp pour des filtres simples ; passez à exp pour du custom.
Comparaison Go vs JavaScript
| Aspect | Go | JavaScript (JSVM) |
|---|---|---|
| Performance | Native, rapide pour gros volumes. | Interprété, suffisant pour hooks légers. |
| Syntaxe | Typé statique, structs pour modèles. | Dynamique, objets/arrays simples. |
| Requêtes | dbx.Builder avec imports explicites. |
$dbx global, plus concis. |
| Transactions | RunInTransaction, imbricable. |
runInTransaction, même logique. |
| Utilisation | App custom complète, builds binaires. | Hooks sans rebuild, idéal prototypage. |
| Complexité | Plus verbeux, mais robuste. | Plus rapide à écrire, moins d'erreurs runtime. |
Go convient aux startups scalant vers des microservices ; JS pour des itérations rapides en SMB. Les deux intègrent les hooks PocketBase (e.g., OnRecordCreateRequest).
Conclusion
Les SDK Go et JS de PocketBase élèvent votre backend au-delà de l'API REST, avec un contrôle fin sur données et DB. Pour une startup, commencez par JS pour valider des idées ; migrez vers Go pour la prod. Testez ces exemples dans un projet local – vous verrez la puissance pour des apps sécurisées et efficaces. Si vous avez des questions, la doc officielle reste la référence.