Vanliga fel med Total.js 5, med fel och rätt kod
Misstag som modeller och människor gör med Total.js 5, var och en med wrong-koden och rätta-koden. paren publiceras också som preferensdata på /preferences.jsonl.
En PATCH som skriver över fält som inte skickades
En PATCH ska bara ändra fälten i begäran. Som standard fylls ett fält som deklarerats i input men inte skickats med standardvärdet för sin typ, och en uppdatering skulle spara det tomma värdet. Alternativet partial: true behåller bara de fält som skickades.
NEWACTION('Wrong/patch', {
name: 'Patch',
input: 'name:String, price:Number',
action: function($, model) {
$.callback(model);
}
});
exports.install = function() {
ROUTE('PATCH /wrong/patch/ --> *Wrong/patch');
};NEWACTION('Right/patch', {
name: 'Patch',
partial: true,
input: 'name:String, price:Number',
action: function($, model) {
$.callback(model);
}
});
exports.install = function() {
ROUTE('PATCH /right/patch/ --> *Right/patch');
};En route med flaggor som aldrig nås
Routes med flaggor kontrolleras efter routen utan flaggor på samma URL. Om båda finns tar routen utan flaggor emot alla begäranden. Deklarera en route och avgör i hanteraren.
exports.install = function() {
ROUTE('GET /wrong/flags/', normal);
ROUTE('GET /wrong/flags/ @xhr', ajax);
};
function normal($) {
$.json({ handler: 'normal' });
}
function ajax($) {
$.json({ handler: 'ajax' });
}exports.install = function() {
ROUTE('GET /right/flags/', answer);
};
function answer($) {
$.json({ handler: $.xhr ? 'ajax' : 'normal' });
}En route för en URL med filändelse
En URL som slutar med en filändelse, som /report.csv, är en filbegäran. En GET-route matchar den inte och begäran slutar med ett 404. Deklarera den med FILE.
exports.install = function() {
ROUTE('GET /wrong-report.csv', report);
};
function report($) {
$.plain('a,b\n1,2\n');
}exports.install = function() {
ROUTE('FILE /right-report.csv', report);
};
function report($) {
$.plain('a,b\n1,2\n');
}En CRON-rad med steg
Skriv minuterna som en lista: 0,15,30,45 matchar exakt de minuterna. check(date) på ett jobb talar om om ett datum matchar, så schemat kan testas utan att vänta.
var job = CRON('*/15 * * * *', function() {});
exports.install = function() {
ROUTE('GET /wrong/cron/', function($) {
$.json({ minute31: job.check(new Date(2026, 0, 5, 9, 31)) });
});
};var job = CRON('0,15,30,45 * * * *', function() {});
exports.install = function() {
ROUTE('GET /right/cron/', function($) {
$.json({ minute31: job.check(new Date(2026, 0, 5, 9, 31)), minute30: job.check(new Date(2026, 0, 5, 9, 30)) });
});
};Att förvänta sig att cache-alternativet för en åtgärd cachar
Spara svaret från en åtgärd med CACHE.set() och läs det med CACHE.get().
var runs = { wrong: 0 };
NEWACTION('Wrong/cached', {
name: 'Cached',
cache: { expire: '1 minute' },
action: function($) {
runs.wrong++;
$.callback({ runs: runs.wrong });
}
});
exports.install = function() {
ROUTE('GET /wrong/cache/ --> *Wrong/cached');
};var runs = { right: 0 };
NEWACTION('Right/cached', {
name: 'Cached',
action: function($) {
var cached = CACHE.get('right-cached');
if (cached)
return $.callback(cached);
runs.right++;
var value = { runs: runs.right };
CACHE.set('right-cached', value, '1 minute');
$.callback(value);
}
});
exports.install = function() {
ROUTE('GET /right/cache/ --> *Right/cached');
};Kod i en mapp som inte laddas
Total.js kör filerna i mapparna som listas på sidan om projektstrukturen. En fil i sources/ körs inte, så kod som ska köras vid start hör hemma i definitions/.
(MAIN.started = MAIN.started || []).push('sources');(MAIN.started = MAIN.started || []).push('definitions');
ROUTE('GET /started/', function($) {
$.json(MAIN.started);
});Att foga text till PATH.root()
PATH.root() returnerar sökvägen utan avslutande snedstreck, så PATH.root() + 'tmp/a.txt' blir /project + tmp/a.txt = /projecttmp/a.txt. Varje mapp har sin egen hjälpfunktion som lägger till avgränsaren.
exports.install = function() {
ROUTE('GET /wrong/path/', function($) {
$.json({ path: PATH.root() + 'tmp/a.txt' });
});
};exports.install = function() {
ROUTE('GET /right/path/', function($) {
$.json({ path: PATH.tmp('a.txt'), root: PATH.root() });
});
};En sträng skickad i en WebSocket-route i textläge
I en route med @text är meddelandena du tar emot strängar, men send(message) kodar fortfarande det som skickas som JSON, så en sträng anländer med citattecken. send(message, true) skickar den som den är.
exports.install = function() {
ROUTE('SOCKET /wrong/text/ @text', function() {
this.on('message', function(client, message) {
client.send('echo: ' + message);
});
});
};exports.install = function() {
ROUTE('SOCKET /right/text/ @text', function() {
this.on('message', function(client, message) {
client.send('echo: ' + message, true);
});
});
};Att förvänta sig att REQUEST() avvisar vid en felstatus
REQUEST() löses med svaret även när statusen är 404 eller 500. Den avvisar bara när själva begäran misslyckas (anslutning vägrad, timeout). Kontrollera response.status.
exports.install = function() {
ROUTE('GET /wrong/request/', async function($) {
try {
var response = await REQUEST({ url: $.hostname('/missing-page/') });
$.json({ ok: true, body: response.body.length > 0 });
} catch (e) {
$.json({ ok: false });
}
});
};exports.install = function() {
ROUTE('GET /right/request/', async function($) {
var response = await REQUEST({ url: $.hostname('/missing-page/') });
$.json({ ok: response.status < 400, status: response.status });
});
};exports.install = function() {
ROUTE('GET /where/', function($) {
$.json({ url: $.hostname('/') });
});
};{
"patch": {
"prompt": "Write a Total.js 5 action for a PATCH route that changes only the fields that were sent.",
"why": "Without `partial: true` a field that was not sent is filled with the default of its type (an empty string), and saving the model overwrites the stored value."
},
"route-flags": {
"prompt": "Write Total.js 5 routes that answer an AJAX request differently from a normal request on the same URL.",
"why": "A route without flags on a URL is checked before a route with flags on the same URL and takes every request, so the flagged route is never reached. Use one route and read `$.xhr` in the handler."
},
"extension-url": {
"prompt": "Write a Total.js 5 route that serves a URL with a file extension, such as /report.csv.",
"why": "A `GET` route never matches a URL with an extension; URLs such as `/report.csv` need a `FILE` route."
},
"cron-step": {
"prompt": "Write a Total.js 5 CRON line that runs every 15 minutes.",
"why": "Write the minutes as a list, for example `0,15,30,45`, so that the job runs exactly at those minutes."
},
"action-cache": {
"prompt": "Write a Total.js 5 action that keeps its answer for a minute so that the same request does not run it again.",
"why": "Keep the result of an action yourself with `CACHE`: `CACHE.set()` stores it and `CACHE.get()` reads it."
},
"folder": {
"prompt": "Where do I put code that must run when a Total.js 5 application starts?",
"why": "Total.js loads and runs the files of `definitions/`, `controllers/`, `actions/`, `schemas/`, `models/`, `modules/`, `extensions/` and `middleware/`. A file in `sources/`, `scripts/` or `transforms/` is not run."
},
"path": {
"prompt": "Write Total.js 5 code that builds the path of a file in the tmp folder.",
"why": "`PATH.root()` has no trailing slash, so joining text to it glues the names together. Use the helper of the folder: `PATH.tmp(name)`."
},
"socket-text": {
"prompt": "Write a Total.js 5 WebSocket route in @text mode that answers with a plain string.",
"why": "In a text route `send(message)` still encodes what it sends as JSON, so the string arrives with quotes. Pass `true` as the second argument to send it as it is."
},
"request-status": {
"prompt": "Write Total.js 5 code that calls another server with REQUEST() and handles an error answer such as 404.",
"why": "REQUEST() resolves with the answer even when the status is an error such as 404; it only rejects when the request itself fails. Check `response.status`."
}
}