Endpoints

Base de données booster

Lire et écrire les enregistrements de la base de données d'un panneau Booster depuis votre propre serveur avec une clé API.

Afficher en Markdown

Un panneau Booster est une petite application web créée dans AYETO Booster Studio. Un panneau peut avoir sa propre base de données, et les endpoints de cette page permettent à votre serveur de lire et de modifier cette base de données avec une clé API : importer des données dans un panneau, les synchroniser avec un autre système ou traiter ce que les utilisateurs du panneau ont saisi.

Tous les endpoints se trouvent sous /api/v3/booster/database/private/. Les panneaux eux-mêmes accèdent à leur base de données par un autre chemin d'accès, qui n'est pas décrit ici.

Concepts

Les panneaux et leur base de données

Chaque panneau a au plus une base de données. Elle existe lorsque le paramètre Accès à la base de données du panneau (détails du panneau dans l'application) vaut Base de données publique ou Base de données privée ; avec Pas de base de données, tous les endpoints de cette page répondent 403. Les modes public et privé peuvent tous deux être utilisés via cette API. La base de données est créée à la première utilisation et est supprimée avec le panneau.

Chaque requête désigne le panneau dans l'en-tête panel-id. L'ID du panneau est affiché, avec un bouton de copie, en haut des détails du panneau dans l'application.

Collections et enregistrements

Une base de données contient des collections, et une collection contient des enregistrements. Les collections n'ont pas besoin d'être créées : une collection existe dès qu'elle contient un enregistrement. Les noms de collection ne peuvent contenir que des lettres, des chiffres et des underscores (orders, contact_requests).

Un enregistrement a exactement deux champs :

Champ Type Description
key UUID Identifiant de l'enregistrement, unique dans les bases de données de tous les panneaux (pas seulement dans sa collection).
value tout type Les données que vous avez stockées. Toute valeur JSON est acceptée ; utilisez un objet si vous voulez filtrer ou trier sur ses champs.

Les enregistrements ne portent aucune autre métadonnée : les réponses n'incluent ni le nom de la collection, ni les horodatages, ni l'auteur. Si vous en avez besoin, stockez-les dans value.

Les endpoints qui travaillent sur un seul enregistrement (get, update, delete et leurs variantes par lot) l'adressent uniquement par sa key ; la collection est déduite de l'enregistrement stocké. Les endpoints qui travaillent sur une collection entière (create, find, count, verrous) prennent le nom de la collection dans le corps.

json
{
  "key": "8f14e45f-ceea-467a-9b1c-4e1f2a6b3c70",
  "value": {
    "customer": {"name": "Jana Nováková", "email": "jana@example.com"},
    "status": "open",
    "priority": 3,
    "created_at": "2026-10-01T09:15:00Z"
  }
}

Qui peut accéder aux données d'un panneau

Les requêtes agissent au nom de l'utilisateur propriétaire de la clé API. Cet utilisateur doit :

  • être propriétaire du panneau (en être le créateur, ou membre du groupe qui le possède, par exemple les administrateurs d'une organisation qui a reçu le panneau d'un partenaire), ou
  • avoir reçu le panneau en partage, directement ou via un groupe auquel il appartient.

Les propriétaires et les utilisateurs avec qui le panneau est partagé (partage en lecture ou en écriture) peuvent lire et écrire la base de données, dans les deux modes : écrire dans la base de données compte comme une utilisation du panneau, pas comme sa modification (modifier le panneau lui-même nécessite toujours un partage en écriture). L'appartenance à l'organisation du panneau ne donne pas accès à elle seule, pas plus que les comptes administrateur AYETO. La clé API doit également porter la portée correspondante :

Portée Endpoints
ayeto.booster.database get, find, count
ayeto.booster.database.write create, create-many, update, update-many, delete, delete-many, lock/acquire, lock/release

La portée d'écriture n'inclut pas la portée de lecture ; une clé qui lit et écrit a besoin des deux.

Les écritures effectuées via cette API sont des écritures dans la base de données du panneau comme les autres : elles démarrent les workflows ayant un déclencheur d'enregistrement booster sur le panneau et exécutent les modules de webhook et de notification par e-mail du panneau.

Règles de collection

Un panneau peut définir des règles de collection qui déterminent ce que les visiteurs anonymes du panneau peuvent faire. Les règles ne s'appliquent qu'en mode base de données publique ; un panneau en mode privé les ignore, et tous les endpoints de cette page fonctionnent sur toutes ses collections.

Pour un panneau en mode public, une seule partie des règles compte pour les requêtes de cette page :

  • Une opération réglée sur none pour une collection (ou pour la règle * qui la couvre) est désactivée pour tout le monde, y compris pour cette API. La requête échoue avec 403.
  • Tous les autres niveaux (public, secret, private) autorisent les requêtes API.
  • Une collection sans règle correspondante est entièrement accessible à l'API.

Les contraintes d'écriture d'une règle (schéma de validation, taille maximale de la valeur, nombre maximal d'enregistrements) ne sont pas appliquées aux écritures effectuées via cette API. Validez les données de votre côté avant de les écrire.

Limites

Limite Valeur
Enregistrements renvoyés par un find jusqu'à 1000 avec pagination (limit_to vaut au plus 1000, limit_from est inférieur à 1000) ; tous les enregistrements correspondants si aucune limite n'est envoyée
Conditions de filtre dans une requête 1000, y compris les conditions à l'intérieur de AND / OR
Imbrication de AND / OR 100 niveaux
Valeurs dans une condition in 100
Valeur de filtre de type chaîne 1000 caractères
Durée de vie d'un verrou plus de 0,1 s, 3600 s par défaut

Les endpoints par lot n'ont pas de nombre maximal fixe d'éléments, mais chaque élément est écrit séparément (voir Créer plusieurs enregistrements) ; limitez les lots à quelques centaines d'éléments pour qu'une requête se termine largement dans le délai d'expiration HTTP.

Interroger les enregistrements

find et count acceptent un objet params facultatif. Ses champs suivent les conventions de requête générales, avec les différences indiquées ici.

Champ Type Obligatoire Description
filters tableau non Conditions, qui doivent toutes être satisfaites. Voir Filtres et ci-dessous.
sort_key chaîne non Champ de tri : key ou value.<field>.
sort_order entier non 0 croissant (par défaut lorsque sort_key est défini), 1 décroissant.
limit_from entier non Index du premier enregistrement à renvoyer, à partir de 0, inférieur à 1000.
limit_to entier non Index qui suit le dernier enregistrement à renvoyer (pas un nombre d'éléments), au plus 1000. Lorsque seul limit_from est envoyé, il vaut limit_from + 100 (au plus 1000).

Champs filtrables et triables

Seuls deux types de noms de champs sont acceptés :

  • key, la clé de l'enregistrement (à comparer avec une chaîne UUID).
  • value.<path>, un champ à l'intérieur de la valeur de l'enregistrement, avec des points pour les objets imbriqués : value.status, value.customer.email.

Tout autre nom échoue avec 422. Les enregistrements dont la valeur ne contient pas le champ (ou n'est pas un objet) ne correspondent simplement pas.

Une condition s'écrit [field, operator, value] avec les opérateurs ==, !=, <, >, <=, >=, regex (toujours insensible à la casse) et in (la valeur est une liste, dont n'importe quel élément peut correspondre). Les conditions peuvent être combinées avec {"AND": [...]} et {"OR": [...]} ; chacun nécessite au moins deux conditions et peut être imbriqué.

json
{
  "collection": "tickets",
  "params": {
    "filters": [
      ["value.status", "in", ["open", "waiting"]],
      {"OR": [
        ["value.priority", ">=", 3],
        ["value.customer.email", "regex", "@example\\.com$"]
      ]}
    ],
    "sort_key": "value.created_at",
    "sort_order": 1,
    "limit_from": 0,
    "limit_to": 50
  }
}

Points à garder à l'esprit lorsque vous filtrez sur des valeurs :

  • Les types doivent correspondre. ["value.priority", ">=", 3] ne correspond pas à un "priority": "3" stocké. Stockez les nombres comme des nombres et les dates comme des chaînes ISO 8601 ou comme des nombres, afin que < et > les comparent correctement.
  • Les chaînes ressemblant à des UUID restent des chaînes dans les conditions value.*, si bien qu'un UUID stocké sous forme de texte est trouvé en tant que texte.
  • Les caractères <, >, " et ' dans une valeur de filtre de type chaîne sont échappés avant la comparaison, si bien qu'une condition sur un texte qui les contient ne correspond pas. Une valeur de filtre de type chaîne ne doit pas non plus commencer par $.

Tri et pagination

Sans sort_key, les enregistrements arrivent du plus récent au plus ancien. Avec sort_key, ils sont triés selon ce champ.

limit_from et limit_to sont des positions dans le résultat : la deuxième page de 50 est donc "limit_from": 50, "limit_to": 100. Comme limit_to ne peut pas dépasser 1000, la pagination par limites n'atteint que les 1000 premiers enregistrements correspondants. Pour aller plus loin, paginez par valeur : triez sur un champ et filtrez sur la dernière valeur reçue, par exemple ["value.created_at", "<", "2026-09-30T12:00:00Z"] avec "sort_key": "value.created_at", "sort_order": 1.

Si vous n'envoyez ni limit_from ni limit_to, find renvoie tous les enregistrements correspondants. Ne le faites que pour des collections que vous savez petites.

count applique les filtres et ignore le tri et la pagination : il renvoie le nombre total d'enregistrements correspondants.

En-têtes de requête et erreurs communs

Tous les endpoints de cette page nécessitent ces en-têtes :

En-tête Description
uni-api-key Votre clé API. Voir Authentification.
panel-id ID du panneau dont vous accédez à la base de données.
Content-Type application/json

Les erreurs sont du JSON de la forme {"detail": "..."} (voir Erreurs). Celles-ci peuvent provenir de tous les endpoints :

Statut detail Cause
401 API key not provided / API key is invalid La clé est vide, inconnue, désactivée ou n'a pas la portée de l'endpoint.
403 permission denied Vous n'êtes pas propriétaire du panneau et il n'est pas partagé avec vous.
403 database access is not allowed for this panel L'accès à la base de données du panneau est réglé sur Pas de base de données.
403 operation '<operation>' is disabled for collection '<collection>' Une règle de collection d'un panneau en mode public règle cette opération sur none. L'opération est create, read, update, delete, count ou lock.
404 panel not found Aucun panneau avec cet ID, ou le panneau est désactivé.
422 erreur de validation L'en-tête panel-id est absent ou n'est pas un UUID, ou le corps ne correspond pas au modèle de requête.
422 Collection name can only contain alphanumeric characters and underscores Nom de collection invalide (Collection cannot be empty pour un nom vide).
429 message de limite de débit Trop de requêtes ; attendez la durée indiquée dans l'en-tête Retry-After. Voir Limites de débit.
500 erreur serveur Échec inattendu ; réessayez plus tard.

Rechercher des enregistrements

Renvoie les enregistrements d'une collection qui correspondent à la requête.

Endpoint POST /api/v3/booster/database/private/find
Portée ayeto.booster.database
Limite de débit par défaut

Requête

Champ Type Obligatoire Description
collection chaîne oui Nom de la collection.
params objet non Filtres, tri et pagination ; voir Interroger les enregistrements. Sans lui, tous les enregistrements de la collection sont renvoyés, du plus récent au plus ancien.

Réponse

Un tableau d'enregistrements (key, value). Une collection inconnue ou vide renvoie [].

Erreurs

Statut detail Cause
422 Field '<field>' is not allowed for filtering or sorting Un filtre ou sort_key désigne autre chose que key ou value.<path>.
422 Each filter condition must be a list of [field, operator, value] Condition mal formée.
422 Operator '<operator>' is not allowed Opérateur inconnu.
422 '<AND/OR>' operator requires a list of at least 2 conditions La valeur de AND / OR n'est pas une liste d'au moins deux conditions.
422 Logical filter must have exactly one key ('AND' or 'OR') Condition logique mal formée, par exemple {} ou un objet avec plusieurs clés.
422 limit_from must be lower than 1000 limit_from vaut 1000 ou plus (la pagination n'atteint que les 1000 premiers enregistrements).
422 Maximum number of filter conditions is 1000 (including conditions inside AND/OR) Trop de conditions.
422 sort_order must be 0 (ASC) or 1 (DESC) sort_order invalide.
422 limit_to cannot exceed 1000 limit_to supérieur à 1000.
422 limit_from cannot be greater than limit_to Plage inversée.

Exemples

bash
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/find" \
  -H "uni-api-key: $AYETO_API_KEY" \
  -H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
  -H "Content-Type: application/json" \
  -d '{
    "collection": "tickets",
    "params": {
      "filters": [["value.status", "==", "open"]],
      "sort_key": "value.priority",
      "sort_order": 1,
      "limit_from": 0,
      "limit_to": 20
    }
  }'
json
[
  {
    "key": "8f14e45f-ceea-467a-9b1c-4e1f2a6b3c70",
    "value": {
      "customer": {"name": "Jana Nováková", "email": "jana@example.com"},
      "status": "open",
      "priority": 3,
      "created_at": "2026-10-01T09:15:00Z"
    }
  },
  {
    "key": "c9f0f895-fb98-4b91-8f2a-6d3e5c1b0a47",
    "value": {
      "customer": {"name": "Petr Svoboda", "email": "petr@example.org"},
      "status": "open",
      "priority": 1,
      "created_at": "2026-10-01T11:40:00Z"
    }
  }
]

Compter les enregistrements

Renvoie le nombre d'enregistrements d'une collection qui correspondent aux filtres.

Endpoint POST /api/v3/booster/database/private/count
Portée ayeto.booster.database
Limite de débit par défaut

Requête

Champ Type Obligatoire Description
collection chaîne oui Nom de la collection.
params objet non Même objet que pour Rechercher des enregistrements. Seuls les filters influent sur le résultat ; le tri et la pagination sont validés mais ignorés.

Réponse

Un entier.

Erreurs

Les erreurs de requête de Rechercher des enregistrements.

Exemples

bash
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/count" \
  -H "uni-api-key: $AYETO_API_KEY" \
  -H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
  -H "Content-Type: application/json" \
  -d '{"collection": "tickets", "params": {"filters": [["value.status", "==", "open"]]}}'
json
42

Obtenir un enregistrement

Renvoie un enregistrement d'après sa clé.

Endpoint POST /api/v3/booster/database/private/get
Portée ayeto.booster.database
Limite de débit par défaut

Requête

Champ Type Obligatoire Description
key UUID oui Clé de l'enregistrement.

Réponse

L'enregistrement.

Erreurs

Statut detail Cause
404 Database record not found La base de données de ce panneau ne contient aucun enregistrement avec cette clé.

Exemples

bash
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/get" \
  -H "uni-api-key: $AYETO_API_KEY" \
  -H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
  -H "Content-Type: application/json" \
  -d '{"key": "8f14e45f-ceea-467a-9b1c-4e1f2a6b3c70"}'
json
{
  "key": "8f14e45f-ceea-467a-9b1c-4e1f2a6b3c70",
  "value": {
    "customer": {"name": "Jana Nováková", "email": "jana@example.com"},
    "status": "open",
    "priority": 3,
    "created_at": "2026-10-01T09:15:00Z"
  }
}

Créer un enregistrement

Ajoute un enregistrement à une collection.

Endpoint POST /api/v3/booster/database/private/create
Portée ayeto.booster.database.write
Limite de débit par défaut

Requête

Champ Type Obligatoire Description
collection chaîne oui Nom de la collection (lettres, chiffres, underscores). La collection est créée avec son premier enregistrement.
value tout type non Les données à stocker. Absent équivaut à null.
key UUID non Clé du nouvel enregistrement. Générée si elle est absente ; elle ne doit être utilisée par aucun enregistrement existant d'aucun panneau (sinon 422).

Réponse

L'enregistrement créé, y compris sa key.

Erreurs

Statut detail Cause
422 a record with key '<key>' already exists La clé envoyée est utilisée par un enregistrement existant (de ce panneau ou d'un autre).
500 error creating database record L'enregistrement n'a pas pu être stocké (rarement, deux requêtes ont créé la même clé au même moment).

Exemples

bash
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/create" \
  -H "uni-api-key: $AYETO_API_KEY" \
  -H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
  -H "Content-Type: application/json" \
  -d '{
    "collection": "tickets",
    "value": {
      "customer": {"name": "Jana Nováková", "email": "jana@example.com"},
      "status": "open",
      "priority": 3,
      "created_at": "2026-10-01T09:15:00Z"
    }
  }'
json
{
  "key": "8f14e45f-ceea-467a-9b1c-4e1f2a6b3c70",
  "value": {
    "customer": {"name": "Jana Nováková", "email": "jana@example.com"},
    "status": "open",
    "priority": 3,
    "created_at": "2026-10-01T09:15:00Z"
  }
}

Créer plusieurs enregistrements

Ajoute plusieurs enregistrements, éventuellement dans des collections différentes.

Endpoint POST /api/v3/booster/database/private/create-many
Portée ayeto.booster.database.write
Limite de débit par défaut

Requête

Le corps est un tableau JSON d'objets de même forme que pour Créer un enregistrement (collection, value, key facultative).

Les éléments sont écrits un par un, dans l'ordre. Le lot n'est pas atomique : si un élément échoue, la requête renvoie l'erreur, les enregistrements qui le précèdent restent créés et les éléments qui le suivent ne sont pas écrits. Un élément dont la key existe déjà arrête le lot avec 422. Avant de relancer un lot en échec, vérifiez ce qui a été écrit, ou envoyez vos propres clés afin de savoir quels éléments existent.

Réponse

Un tableau des enregistrements créés, dans l'ordre de la requête.

Erreurs

Les erreurs de Créer un enregistrement, pour le premier élément en échec.

Exemples

bash
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/create-many" \
  -H "uni-api-key: $AYETO_API_KEY" \
  -H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
  -H "Content-Type: application/json" \
  -d '[
    {"collection": "products", "key": "0b6e8c1a-5d2f-4e3b-9a7c-1f4d6e8a2b30", "value": {"sku": "MUG-01", "name": "Mug", "quantity": 12}},
    {"collection": "products", "key": "5a9d3f2e-8c1b-4a6e-b7d0-3e2f1c9a8b54", "value": {"sku": "TEE-M", "name": "T-shirt M", "quantity": 40}}
  ]'
json
[
  {"key": "0b6e8c1a-5d2f-4e3b-9a7c-1f4d6e8a2b30", "value": {"sku": "MUG-01", "name": "Mug", "quantity": 12}},
  {"key": "5a9d3f2e-8c1b-4a6e-b7d0-3e2f1c9a8b54", "value": {"sku": "TEE-M", "name": "T-shirt M", "quantity": 40}}
]

Mettre à jour un enregistrement

Remplace la valeur d'un enregistrement.

Endpoint POST /api/v3/booster/database/private/update
Portée ayeto.booster.database.write
Limite de débit par défaut

Requête

Champ Type Obligatoire Description
key UUID oui Clé de l'enregistrement.
value tout type non La nouvelle valeur. Elle remplace entièrement la valeur stockée ; les champs que vous omettez sont supprimés. Absent équivaut à null.

Pour modifier un seul champ, lisez l'enregistrement, modifiez le champ et renvoyez la valeur entière. Si d'autres clients peuvent écrire le même enregistrement au même moment, faites-le sous un verrou.

Réponse

L'enregistrement mis à jour.

Erreurs

Statut detail Cause
404 Database record not found La base de données de ce panneau ne contient aucun enregistrement avec cette clé.

Exemples

bash
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/update" \
  -H "uni-api-key: $AYETO_API_KEY" \
  -H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "8f14e45f-ceea-467a-9b1c-4e1f2a6b3c70",
    "value": {
      "customer": {"name": "Jana Nováková", "email": "jana@example.com"},
      "status": "closed",
      "priority": 3,
      "created_at": "2026-10-01T09:15:00Z"
    }
  }'
json
{
  "key": "8f14e45f-ceea-467a-9b1c-4e1f2a6b3c70",
  "value": {
    "customer": {"name": "Jana Nováková", "email": "jana@example.com"},
    "status": "closed",
    "priority": 3,
    "created_at": "2026-10-01T09:15:00Z"
  }
}

Mettre à jour plusieurs enregistrements

Remplace les valeurs de plusieurs enregistrements.

Endpoint POST /api/v3/booster/database/private/update-many
Portée ayeto.booster.database.write
Limite de débit par défaut

Requête

Le corps est un tableau JSON d'objets de même forme que pour Mettre à jour un enregistrement (key, value). Les éléments sont écrits un par un, dans l'ordre, et le lot n'est pas atomique : un élément en échec arrête la requête, les éléments qui le précèdent restent mis à jour.

Réponse

Un tableau des enregistrements mis à jour, dans l'ordre de la requête.

Erreurs

Les erreurs de Mettre à jour un enregistrement, pour le premier élément en échec.

Exemples

bash
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/update-many" \
  -H "uni-api-key: $AYETO_API_KEY" \
  -H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
  -H "Content-Type: application/json" \
  -d '[
    {"key": "0b6e8c1a-5d2f-4e3b-9a7c-1f4d6e8a2b30", "value": {"sku": "MUG-01", "name": "Mug", "quantity": 10}},
    {"key": "5a9d3f2e-8c1b-4a6e-b7d0-3e2f1c9a8b54", "value": {"sku": "TEE-M", "name": "T-shirt M", "quantity": 37}}
  ]'
json
[
  {"key": "0b6e8c1a-5d2f-4e3b-9a7c-1f4d6e8a2b30", "value": {"sku": "MUG-01", "name": "Mug", "quantity": 10}},
  {"key": "5a9d3f2e-8c1b-4a6e-b7d0-3e2f1c9a8b54", "value": {"sku": "TEE-M", "name": "T-shirt M", "quantity": 37}}
]

Supprimer un enregistrement

Supprime un enregistrement.

Endpoint POST /api/v3/booster/database/private/delete
Portée ayeto.booster.database.write
Limite de débit par défaut

Requête

Champ Type Obligatoire Description
key UUID oui Clé de l'enregistrement.

Réponse

null.

Erreurs

Statut detail Cause
404 Database record not found La base de données de ce panneau ne contient aucun enregistrement avec cette clé (y compris lorsqu'il a déjà été supprimé).

Exemples

bash
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/delete" \
  -H "uni-api-key: $AYETO_API_KEY" \
  -H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
  -H "Content-Type: application/json" \
  -d '{"key": "8f14e45f-ceea-467a-9b1c-4e1f2a6b3c70"}'

Supprimer plusieurs enregistrements

Supprime plusieurs enregistrements.

Endpoint POST /api/v3/booster/database/private/delete-many
Portée ayeto.booster.database.write
Limite de débit par défaut

Requête

Le corps est un tableau JSON d'objets avec un champ key, comme pour Supprimer un enregistrement. Les enregistrements sont supprimés un par un, dans l'ordre ; un élément en échec (par exemple une clé qui n'existe pas) arrête la requête, et les enregistrements qui le précèdent restent supprimés.

Réponse

null.

Erreurs

Les erreurs de Supprimer un enregistrement, pour le premier élément en échec.

Exemples

bash
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/delete-many" \
  -H "uni-api-key: $AYETO_API_KEY" \
  -H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
  -H "Content-Type: application/json" \
  -d '[
    {"key": "0b6e8c1a-5d2f-4e3b-9a7c-1f4d6e8a2b30"},
    {"key": "5a9d3f2e-8c1b-4a6e-b7d0-3e2f1c9a8b54"}
  ]'

Verrous

Les verrous permettent à plusieurs clients (vos serveurs, le panneau lui-même) d'accéder à tour de rôle aux mêmes données. Un verrou a une durée de vie et est de l'un des deux types suivants :

  • Verrou d'enregistrement : collection et key. Utilisez la collection réelle de l'enregistrement ; un verrou pris sous un autre nom de collection ne protège pas l'enregistrement.
  • Verrou de collection : collection sans key.

Les verrous sont consultatifs : le serveur ne les vérifie pas. get, find, count, create, update, delete et leurs variantes par lot passent, qu'un enregistrement ou une collection soit verrouillé ou non. Un verrou fait seulement attendre les autres appels lock/acquire pour le même verrou ; il ne protège donc les données que si chaque client qui les écrit prend d'abord le verrou ; cette coordination incombe au panneau et à votre code.

  • Les verrous d'enregistrement et de collection sont indépendants. Détenir un verrou de collection n'empêche personne de prendre un verrou d'enregistrement dans cette collection, et inversement.
  • N'importe qui peut libérer un verrou. release libère le verrou quel que soit celui qui l'a pris, et un second acquire d'un verrou que vous détenez déjà attend comme pour celui de n'importe qui d'autre. Ne libérez un verrou que depuis le code qui l'a acquis.
  • Les verrous expirent. Chaque verrou est libéré automatiquement après son ttl, même s'il n'a jamais été libéré. Choisissez un TTL plus long que la durée de votre traitement, mais assez court pour qu'un client planté ne bloque pas les autres trop longtemps.

Le verrouillage correspond à l'opération lock des règles de collection ; les deux endpoints nécessitent la portée d'écriture et le même accès au panneau que l'écriture.

Acquérir un verrou

Prend un verrou d'enregistrement ou de collection, en attendant qu'il soit libre.

Endpoint POST /api/v3/booster/database/private/lock/acquire
Portée ayeto.booster.database.write
Limite de débit par défaut

Requête

Champ Type Obligatoire Description
collection chaîne oui Nom de la collection.
key UUID non Clé de l'enregistrement. Omettez-la pour prendre le verrou de collection.
acquire_timeout nombre non Nombre de secondes d'attente du verrou. 0 échoue immédiatement si le verrou est pris. S'il est absent, la requête attend aussi longtemps que nécessaire, jusqu'au TTL restant du détenteur actuel ; envoyez toujours une valeur plus courte que votre délai d'expiration HTTP.
ttl nombre non Nombre de secondes après lesquelles le verrou est libéré automatiquement. Doit être supérieur à 0.1. 3600 par défaut.

Réponse

null, une fois le verrou à vous.

Erreurs

Statut detail Cause
423 Failed to acquire lock for collection '<collection>' and key '<key>' Le verrou est resté pris pendant acquire_timeout secondes (<key> vaut None pour un verrou de collection). Réessayez plus tard.
422 erreur de validation ttl vaut 0.1 ou moins.

Exemples

bash
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/lock/acquire" \
  -H "uni-api-key: $AYETO_API_KEY" \
  -H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
  -H "Content-Type: application/json" \
  -d '{"collection": "products", "key": "0b6e8c1a-5d2f-4e3b-9a7c-1f4d6e8a2b30", "acquire_timeout": 10, "ttl": 30}'

Libérer un verrou

Libère un verrou d'enregistrement ou de collection, quel que soit son détenteur.

Endpoint POST /api/v3/booster/database/private/lock/release
Portée ayeto.booster.database.write
Limite de débit par défaut

Requête

Champ Type Obligatoire Description
collection chaîne oui Nom de la collection, tel qu'envoyé à lock/acquire.
key UUID non Clé de l'enregistrement, telle qu'envoyée à lock/acquire. Omettez-la pour le verrou de collection.

Réponse

null. Libérer un verrou qui n'est pas pris (ou qui a expiré) réussit également.

Exemples

bash
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/lock/release" \
  -H "uni-api-key: $AYETO_API_KEY" \
  -H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
  -H "Content-Type: application/json" \
  -d '{"collection": "products", "key": "0b6e8c1a-5d2f-4e3b-9a7c-1f4d6e8a2b30"}'

Lecture-modification-écriture sous verrou

update remplace la valeur entière : deux clients qui lisent chacun un enregistrement, le modifient et le réécrivent peuvent donc écraser mutuellement leurs modifications. Prenez le verrou d'enregistrement autour de toute la séquence et libérez-le dans un bloc finally ; chaque client qui écrit l'enregistrement doit faire de même :

python
import os
import time

import requests

BASE_URL = "https://ayeto.ai/api/v3/booster/database/private"
HEADERS = {
    "uni-api-key": os.environ["AYETO_API_KEY"],
    "panel-id": "3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90",
}


def call(path: str, body):
    response = requests.post(f"{BASE_URL}/{path}", json=body, headers=HEADERS, timeout=30)
    response.raise_for_status()
    return response.json()


def change_stock(key: str, delta: int, attempts: int = 3) -> dict:
    """Add `delta` to the quantity of a product record without losing concurrent changes."""
    lock = {"collection": "products", "key": key}
    for attempt in range(attempts):
        try:
            # wait at most 10 s; the lock frees itself after 30 s if this process dies
            call("lock/acquire", {**lock, "acquire_timeout": 10, "ttl": 30})
            break
        except requests.HTTPError as e:
            if e.response.status_code != 423 or attempt == attempts - 1:
                raise
            time.sleep(2)

    try:
        record = call("get", {"key": key})
        value = record["value"]
        value["quantity"] = value.get("quantity", 0) + delta
        return call("update", {"key": key, "value": value})
    finally:
        call("lock/release", lock)


print(change_stock("0b6e8c1a-5d2f-4e3b-9a7c-1f4d6e8a2b30", -2))