0Pricing
Lua Academy · Leçon

Objets d’erreur structurés

Transmettez des tables comme objets d’erreur pour communiquer le type et le contexte.

Objets d’erreur structurés est une leçon Lua Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Lua Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Lua Academy comprend 4 leçons au total.

Pourquoi utiliser des erreurs structurées ?

Les erreurs sous forme de simples chaînes sont difficiles à traiter par programmation. Les objets d’erreur structurés (tables) contiennent des informations de type et des données de contexte ; les appelants peuvent les examiner et agir en conséquence. Cela permet de distribuer le traitement selon l’erreur sans analyser des chaînes.

-- Plain string: hard to handle programmatically
error("database error: connection refused")

-- Structured: type + data
error({
  type = "DatabaseError",
  code = "CONN_REFUSED",
  host = "localhost",
  port = 5432,
  message = "connection refused"
})

Schéma de constructeur d’erreurs

Créez une fonction fabrique d’erreurs pour chaque type d’erreur. La fabrique construit une table avec des champs cohérents : type, message et tout contexte pertinent. Une métaméthode __tostring permet d’afficher correctement l’erreur.

local ErrorMT = {__tostring = function(e)
  return string.format("[%s] %s", e.type, e.message)
end}

local function makeError(errType, msg, data)
  local e = {type=errType, message=msg}
  if data then for k,v in pairs(data) do e[k]=v end end
  return setmetatable(e, ErrorMT)
end

local E = {
  notFound = function(name) return makeError("NOT_FOUND","not found: "..name,{name=name}) end,
  badInput = function(msg,field) return makeError("BAD_INPUT",msg,{field=field}) end,
}

local ok, err = pcall(error, E.notFound("user:42"))
print(tostring(err))   -- [NOT_FOUND] not found: user:42

Vérifier le type des objets d’erreur

Après avoir capturé une erreur, vérifiez qu’il s’agit d’une table contenant un champ de type connu. Vous pouvez ainsi distribuer différentes stratégies de récupération selon le type d’erreur, sans dépendre de la recherche de motifs dans des chaînes.

local function handleRequest(fn)
  local ok, err = pcall(fn)
  if ok then return true end
  if type(err) == "table" then
    if err.type == "NOT_FOUND" then
      print("404: " .. err.message)
    elseif err.type == "BAD_INPUT" then
      print("400: " .. err.message .. " (field: " .. (err.field or "?") .. ")")
    else
      print("500: unhandled error: " .. tostring(err))
    end
  else
    print("500: " .. tostring(err))
  end
  return false
end

Hiérarchie d’erreurs

Simulez une hiérarchie d’erreurs en vérifiant les champs is_a ou en utilisant des métatables. Les types d’erreurs enfants héritent des champs du type parent et peuvent être traités comme le parent par le code qui n’a pas besoin des détails.

local function isError(e, errType)
  if type(e) ~= "table" then return false end
  return e.type == errType or e.parentType == errType
end

local function makeDbError(code, msg)
  return {type="DbError:"..code, parentType="DbError", code=code, message=msg}
end

local err = makeDbError("TIMEOUT","query timed out")
print(isError(err, "DbError"))          -- true
print(isError(err, "DbError:TIMEOUT"))  -- true
print(isError(err, "NetworkError"))     -- false

Encapsuler les erreurs

Lors de la capture et de la relance d’une erreur, encapsulez l’erreur d’origine pour ajouter du contexte sans la perdre. L’encapsuleur possède son propre type et conserve l’erreur d’origine comme cause.

local function wrapError(msg, cause)
  return {
    type = "WrappedError",
    message = msg,
    cause = cause,
  }
end

local function loadConfig(path)
  local ok, err = pcall(function()
    local f = assert(io.open(path,"r"))
    local content = f:read("a")
    f:close()
    return content
  end)
  if not ok then
    error(wrapError("failed to load config: "..path, err))
  end
end

local ok2, e = pcall(loadConfig, "missing.cfg")
if not ok2 then
  print(e.message)
  print("Caused by:", tostring(e.cause))
end

Codes d’erreur ou types d’erreur

Deux conventions sont courantes : les codes d’erreur (numériques, comme les codes d’état HTTP) et les chaînes de type d’erreur (noms sémantiques). Les codes d’erreur sont faciles à comparer numériquement ; les chaînes de type sont explicites. De nombreux systèmes utilisent les deux.

local STATUS = {OK=200, NOT_FOUND=404, SERVER_ERROR=500, BAD_REQUEST=400}

local function makeStatusError(status, msg)
  return {status=status, message=msg, type="HTTPError"}
end

local function handleError(e)
  if e.status == STATUS.NOT_FOUND then
    print("Resource not found:", e.message)
  elseif e.status >= 500 then
    print("Server error:", e.message)
  else
    print("Error", e.status, e.message)
  end
end

handleError(makeStatusError(404, "user not found"))

Pile d’erreurs (chaîne des causes)

Lorsqu’une erreur est causée par une autre, reliez-les. Vous obtenez ainsi une vue complète de ce qui s’est mal passé à chaque couche de l’application. Défaites la chaîne pour journaliser ou afficher l’historique complet de l’erreur.

local function unwindCause(e, depth)
  depth = depth or 0
  local pad = string.rep("  ", depth)
  if type(e) == "table" then
    print(pad .. (e.type or "Error") .. ": " .. (e.message or "?"))
    if e.cause then unwindCause(e.cause, depth+1) end
  else
    print(pad .. tostring(e))
  end
end

local inner = {type="IoError", message="permission denied"}
local outer = {type="ConfigError", message="cannot load config", cause=inner}
unwindCause(outer)
-- ConfigError: cannot load config
--   IoError: permission denied

Erreur dans le contexte d’un rappel

Lorsque des erreurs surviennent dans des rappels (gestionnaires d’événements, itérateurs), elles se propagent jusqu’à l’appelant du rappel. Utilisez pcall pour les intercepter et les signaler avec le contexte indiquant quel rappel a échoué.

local function runCallbacks(callbacks, data)
  local errors = {}
  for name, fn in pairs(callbacks) do
    local ok, err = pcall(fn, data)
    if not ok then
      errors[#errors+1] = {callback=name, error=err}
    end
  end
  return errors
end

local cbs = {
  validate = function(d) assert(d.name, "name required") end,
  transform = function(d) d.name = d.name:upper() end,
}

local errs = runCallbacks(cbs, {})
for _, e in ipairs(errs) do
  print(e.callback, "->", e.error)
end

Afficher les détails d’une erreur

Un utilitaire qui affiche un objet d’erreur de manière structurée et lisible, en gérant à la fois les erreurs sous forme de chaîne et celles sous forme de table. Il est utile aux limites de l’application, là où les erreurs sont journalisées ou affichées aux utilisateurs.

local function printError(err, prefix)
  prefix = prefix or "Error"
  if type(err) ~= "table" then
    print(prefix .. ": " .. tostring(err))
    return
  end
  print(prefix .. " [" .. (err.type or "unknown") .. "]")
  print("  Message: " .. (err.message or "?"))
  for k, v in pairs(err) do
    if k ~= "type" and k ~= "message" and k ~= "cause" then
      print("  " .. k .. ": " .. tostring(v))
    end
  end
  if err.cause then printError(err.cause, "  Caused by") end
end

Assertions avec des erreurs structurées

Créez un assertT (assertion avec erreurs typées) qui déclenche une erreur structurée au lieu d’une simple chaîne. Il devient ainsi facile de tester des types d’erreur précis dans le code appelant.

local function assertT(cond, errType, msg, data)
  if not cond then
    local e = {type=errType, message=msg}
    if data then for k,v in pairs(data) do e[k]=v end end
    error(e, 2)
  end
  return cond
end

local function createUser(name, age)
  assertT(type(name)=="string", "BAD_INPUT", "name must be string", {field="name"})
  assertT(age >= 0 and age <= 150, "BAD_INPUT", "invalid age", {field="age", value=age})
  return {name=name, age=age}
end

local ok, err = pcall(createUser, "Alice", -5)
if not ok then print(err.type, err.field, err.value) end

Vérification rapide

Quel est le principal avantage de transmettre une table à error() plutôt qu’une chaîne ?

Récapitulatif : erreurs structurées

Résumé :

  • Transmettez des tables à error() pour obtenir des erreurs structurées et inspectables
  • Incluez : le type, le message et les champs de contexte pertinents
  • Ajoutez __tostring pour obtenir un affichage lisible
  • Encapsulez les erreurs pour ajouter du contexte sans perdre la cause
  • Distribuez le traitement selon le type dans les gestionnaires : vérifiez err.type, et non des motifs de chaîne

Questions Fréquemment Posées

La leçon « Objets d’erreur structurés » est-elle gratuite ?

Oui — le texte complet de « Objets d’erreur structurés » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Lua Academy, passe à CoddyKit PRO. Le cours Lua Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Objets d’erreur structurés » ?

Transmettez des tables comme objets d’erreur pour communiquer le type et le contexte. Tu pratiques Lua Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Lua Academy ?

Aucune expérience préalable n'est requise. Lua Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.

Combien de temps prend la leçon « Objets d’erreur structurés » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Lua Academy ?

Oui. Chaque leçon Lua Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. La fonction error()
  2. Appels protégés avec pcall
  3. xpcall et gestionnaires de messages
  4. Objets d’erreur structurés
← Retour à Lua Academy