ForgeDokumentáció
hu

Dokumentáció

Általános hibák a Total.js 5-vel, téves és helyes kódmal

Total.js 5 · total5@0.0.19 guidemistakespitfalls Total.js 5-tel lefuttatva

A hibák, amelyeket a modellek és az emberek elkövetnek Total.js 5, mindegyik a wrong kódot és a **jobb* kódot tartalmazza. /preferences.jsonl.

Egy PATCH, amely felülírja a nem elküldött mezőket

A PATCH-nek csak a kérés mezőit szabad módosítania. Alapértelmezés szerint az input-ban deklarált, de nem elküldött mező a típusa alapértelmezett értékével töltődik ki, és a frissítés ezt az üres értéket mentené el. A partial: true beállítás csak az elküldött mezőket tartja meg.

controllers/wrong-patch.js
NEWACTION('Wrong/patch', {
	name: 'Patch',
	input: 'name:String, price:Number',
	action: function($, model) {
		$.callback(model);
	}
});

exports.install = function() {
	ROUTE('PATCH /wrong/patch/ --> *Wrong/patch');
};
controllers/right-patch.js
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');
};

Egy jelzőkkel ellátott útvonal, amely sosem érhető el

A jelzőkkel ellátott útvonalakat az ugyanazon az URL-en lévő, jelzők nélküli útvonal után ellenőrzi a rendszer. Ha mindkettő létezik, a jelzők nélküli útvonal minden kérést átvesz. Deklarálj egy útvonalat, és a kezelőben dönts.

controllers/wrong-route-flags.js
exports.install = function() {
	ROUTE('GET /wrong/flags/', normal);
	ROUTE('GET /wrong/flags/ @xhr', ajax);
};

function normal($) {
	$.json({ handler: 'normal' });
}

function ajax($) {
	$.json({ handler: 'ajax' });
}
controllers/right-route-flags.js
exports.install = function() {
	ROUTE('GET /right/flags/', answer);
};

function answer($) {
	$.json({ handler: $.xhr ? 'ajax' : 'normal' });
}

Egy útvonal kiterjesztéssel rendelkező URL-hez

A kiterjesztéssel végződő URL, például a /report.csv, fájlkérés. Egy GET útvonal nem illeszkedik rá, és a kérés 404-gyel végződik. Deklaráld a FILE-lal.

controllers/wrong-extension-url.js
exports.install = function() {
	ROUTE('GET /wrong-report.csv', report);
};

function report($) {
	$.plain('a,b\n1,2\n');
}
controllers/right-extension-url.js
exports.install = function() {
	ROUTE('FILE /right-report.csv', report);
};

function report($) {
	$.plain('a,b\n1,2\n');
}

Egy CRON-sor lépésközzel

A perceket listaként írd: a 0,15,30,45 pontosan ezekre a percekre illik. Egy feladat check(date) hívása megmondja, hogy egy dátum illik-e, így az ütemezés várakozás nélkül tesztelhető.

controllers/wrong-cron-step.js
var job = CRON('*/15 * * * *', function() {});

exports.install = function() {
	ROUTE('GET /wrong/cron/', function($) {
		$.json({ minute31: job.check(new Date(2026, 0, 5, 9, 31)) });
	});
};
controllers/right-cron-step.js
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)) });
	});
};

Azt várni, hogy egy művelet cache beállítása gyorsítótáraz

Egy akció válaszát tárold a CACHE.set() segítségével, és olvasd a CACHE.get() hívással.

controllers/wrong-action-cache.js
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');
};
controllers/right-action-cache.js
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');
};

Kód egy olyan mappában, amely nincs betöltve

A Total.js a projektstruktúra oldalon felsorolt mappák fájljait futtatja. A sources/ mappában lévő fájl nem fut le, ezért az induláskor futtatandó kód a definitions/ mappába való.

sources/wrong-folder.js
(MAIN.started = MAIN.started || []).push('sources');
definitions/right-folder.js
(MAIN.started = MAIN.started || []).push('definitions');

ROUTE('GET /started/', function($) {
	$.json(MAIN.started);
});

Szöveg hozzáfűzése a PATH.root()-hoz

A PATH.root() záró perjel nélküli útvonalat ad vissza, így a PATH.root() + 'tmp/a.txt' /project + tmp/a.txt = /projecttmp/a.txt lesz. Minden mappának saját segédfüggvénye van, amely hozzáadja az elválasztót.

controllers/wrong-path.js
exports.install = function() {
	ROUTE('GET /wrong/path/', function($) {
		$.json({ path: PATH.root() + 'tmp/a.txt' });
	});
};
controllers/right-path.js
exports.install = function() {
	ROUTE('GET /right/path/', function($) {
		$.json({ path: PATH.tmp('a.txt'), root: PATH.root() });
	});
};

Karakterlánc küldése egy szöveges módú WebSocket-útvonalon

A @text útvonalon a kapott üzenetek karakterláncok, de a send(message) továbbra is JSON-ként kódolja, amit küld, így a karakterlánc idézőjelekkel érkezik meg. A send(message, true) változtatás nélkül küldi el.

controllers/wrong-socket-text.js
exports.install = function() {
	ROUTE('SOCKET /wrong/text/ @text', function() {
		this.on('message', function(client, message) {
			client.send('echo: ' + message);
		});
	});
};
controllers/right-socket-text.js
exports.install = function() {
	ROUTE('SOCKET /right/text/ @text', function() {
		this.on('message', function(client, message) {
			client.send('echo: ' + message, true);
		});
	});
};

Azt várni, hogy a REQUEST() hibás állapotkódnál elutasít

A REQUEST() akkor is a válasszal teljesül, ha az állapotkód 404 vagy 500. Csak akkor utasít el, ha maga a kérés meghiúsul (a kapcsolat elutasítva, időtúllépés). Ellenőrizd a response.status értékét.

controllers/wrong-request-status.js
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 });
		}
	});
};
controllers/right-request-status.js
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 });
	});
};
controllers/where.js
exports.install = function() {
	ROUTE('GET /where/', function($) {
		$.json({ url: $.hostname('/') });
	});
};
pitfalls.json
{
 "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`."
 }
}