Gestructureerde foutobjecten
Geef tables door als foutobjecten om type en context over te brengen
Gestructureerde foutobjecten is een gratis Lua Academy-les op CoddyKit. Dit is les 4 van 4. Je kunt 3 lessen uit dit leerpad gratis volledig lezen — daarna ontgrendelt CoddyKit PRO alle lessen, plus praktische oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Lua Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Lua Academy bevat in totaal 4 lessen.
Waarom gestructureerde fouten?
Eenvoudige tekenreeksfouten zijn moeilijk programmatisch af te handelen. Gestructureerde foutobjecten (tabellen) bevatten type-informatie en contextgegevens en kunnen door aanroepers worden onderzocht en verwerkt. Zo kun je fouten afhandelen op basis van hun type, zonder tekenreeksen te parseren.
-- 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"
})Patroon voor foutconstructors
Maak voor elk fouttype een fabrieksfunctie voor fouten. De fabriek bouwt een tabel met vaste velden: type, message en relevante context. Met een __tostring-metamethode wordt de fout netjes afgedrukt.
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:42Foutobjecten op type controleren
Controleer na het afvangen van een fout of deze een tabel is met een bekend typeveld. Zo kun je verschillende herstelstrategieën kiezen op basis van het fouttype, zonder afhankelijk te zijn van patroonherkenning in tekenreeksen.
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
endFouthiërarchie
Simuleer een fouthiërarchie door is_a-velden te controleren of metatabellen te gebruiken. Onderliggende fouttypen nemen de velden van het bovenliggende type over en kunnen door code die geen details nodig heeft als het bovenliggende type worden behandeld.
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")) -- falseFouten omwikkelen
Wanneer je een fout afvangt en opnieuw gooit, wikkel je de oorspronkelijke fout om context toe te voegen zonder deze kwijt te raken. De omwikkeling heeft een eigen type en bevat de oorspronkelijke fout als oorzaak.
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))
endFoutcodes versus fouttypen
Twee veelgebruikte conventies zijn foutcodes (numeriek, zoals HTTP-statuscodes) en tekenreeksen voor fouttypen (semantische namen). Foutcodes zijn eenvoudig numeriek te vergelijken; tekenreeksen voor typen beschrijven zichzelf. Veel systemen gebruiken beide.
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"))Foutenstack (oorzakenketen)
Wanneer een fout door een andere fout is veroorzaakt, koppel je ze aan elkaar. Zo krijg je een volledig beeld van wat er in elke laag van de toepassing is misgegaan. Pak de keten uit om het volledige foutverhaal te loggen of weer te geven.
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 deniedFouten in callbackcontext
Wanneer fouten optreden in callbacks (gebeurtenisafhandelaars, iterators), worden ze doorgegeven aan de aanroeper van de callback. Gebruik pcall om ze af te vangen en te rapporteren met context over welke callback is mislukt.
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)
endFoutdetails afdrukken
Een helper die een foutobject op een gestructureerde, leesbare manier afdrukt en zowel tekenreeks- als tabelfouten verwerkt. Dit is nuttig op toepassingsgrenzen waar fouten worden gelogd of aan gebruikers worden getoond.
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
endAsserties met gestructureerde fouten
Maak een assertT (assertie met getypeerde fouten) die een gestructureerde fout veroorzaakt in plaats van een gewone tekenreeks. Zo kun je in aanroepers eenvoudig op specifieke fouttypen testen.
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) endKorte controle
Wat is het belangrijkste voordeel van het doorgeven van een tabel aan error() in plaats van een tekenreeks?
Samenvatting: gestructureerde fouten
Samenvatting:
- Geef tabellen door aan
error()voor gestructureerde, inspecteerbare fouten - Neem type, message en relevante contextvelden op
- Voeg
__tostringtoe voor leesbare uitvoer - Wikkel fouten om context toe te voegen zonder de oorzaak kwijt te raken
- Gebruik type-dispatch in handlers: controleer
err.type, geen tekenreekspatronen
Leer Lua met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 40
- Lessen
- 159
Veelgestelde vragen
Is de les “Gestructureerde foutobjecten” gratis?
Ja — je kunt hier op het web alle 3 lessen van het leerpad Lua Academy, waaronder “Gestructureerde foutobjecten”, gratis volledig lezen. Daarna ontgrendelt CoddyKit PRO alle lessen, plus interactieve oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. De cursus Lua Academy bevat in totaal 4 lessen.
Wat leer ik in “Gestructureerde foutobjecten”?
Geef tables door als foutobjecten om type en context over te brengen Je oefent met Lua Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met Lua Academy te beginnen?
Ervaring vooraf is niet nodig. Lua Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 4 van 4.
Hoe lang duurt de les “Gestructureerde foutobjecten”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over Lua Academy?
Ja. Elke les over Lua Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- De functie error()
- Beveiligde aanroepen met pcall
- xpcall en meldingshandlers
- Gestructureerde foutobjecten