Algemene fouten met Total.js 5, met de verkeerde en juiste code
De fouten die mensen en modellen maken Total.js 5, elk met de wrong code en de right code. /preferences.jsonl.
Een PATCH die niet verzonden velden overschrijft
Een PATCH zou alleen de velden van het verzoek moeten wijzigen. Standaard wordt een veld dat in input is gedeclareerd maar niet is verzonden, gevuld met de standaardwaarde van zijn type, en een update zou die lege waarde opslaan. De optie partial: true bewaart alleen de velden die zijn verzonden.
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');
};Een route met flags die nooit wordt bereikt
Routes met flags worden gecontroleerd na de route zonder flags op dezelfde URL. Als beide bestaan, neemt de route zonder flags elk verzoek over. Declareer één route en beslis in de handler.
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' });
}Een route voor een URL met extensie
Een URL die eindigt op een extensie, zoals /report.csv, is een bestandsverzoek. Een GET-route komt er niet mee overeen en het verzoek eindigt met een 404. Declareer het met 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');
}Een CRON-regel met een stap
Schrijf de minuten als lijst: 0,15,30,45 komt precies overeen met die minuten. De check(date) van een job vertelt of een datum past, zodat het schema zonder wachten getest kan worden.
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)) });
});
};Verwachten dat de cache-optie van een actie cachet
Bewaar het antwoord van een actie met CACHE.set() en lees het met 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');
};Code in een map die niet wordt geladen
Total.js voert de bestanden uit van de mappen die op de pagina over de projectstructuur staan. Een bestand in sources/ wordt niet uitgevoerd, dus code die bij het starten moet draaien hoort in definitions/.
(MAIN.started = MAIN.started || []).push('sources');(MAIN.started = MAIN.started || []).push('definitions');
ROUTE('GET /started/', function($) {
$.json(MAIN.started);
});Tekst aan PATH.root() plakken
PATH.root() geeft het pad zonder slash aan het einde terug, dus PATH.root() + 'tmp/a.txt' wordt /project + tmp/a.txt = /projecttmp/a.txt. Elke map heeft zijn eigen helper die het scheidingsteken toevoegt.
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() });
});
};Een string verzonden in een WebSocket-route in tekstmodus
In een route met @text zijn de berichten die je ontvangt strings, maar send(message) codeert wat het verzendt nog steeds als JSON, dus een string komt met aanhalingstekens aan. send(message, true) verstuurt hem zoals hij is.
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);
});
});
};Verwachten dat REQUEST() weigert bij een foutstatus
REQUEST() wordt opgelost met het antwoord, ook als de status 404 of 500 is. Hij weigert alleen als het verzoek zelf mislukt (verbinding geweigerd, time-out). Controleer 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`."
}
}