ForgeTotal.js 5
it

Total.js 5

Costruire una risorsa REST completa con le azioni

Total.js 5 · total5@0.0.19 actionscrudrestnosql Eseguita con Total.js 5

Una risorsa REST è fatta di sei operazioni: elenco (query), read, insert, update (sostituire), patch (modificare pochi campi) e remove. In Total.js ciascuna è un'azione con la propria validazione, così la tabella delle rotte resta una semplice mappa da URL ad azione. params valida l'id dell'URL, query i filtri dell'elenco, input il corpo. All'interno di un'azione $.params, $.query e il corpo validato (secondo argomento di action) sono già valori puliti.

Segnala un record mancante con $.invalid(404): risponde con il codice di stato e un errore JSON, nello stesso modo per ogni azione. $.success() risponde { "success": true } e $.callback(value) risponde con un valore, che viene inoltre filtrato dall'output dell'azione. UID() crea l'id di un nuovo record.

patch richiede partial: true. Senza di esso un campo non inviato viene comunque riempito con il valore predefinito del suo tipo ('' per una String), e update() sovrascriverebbe il valore salvato con quel testo vuoto. Con partial: true raggiungono l'azione solo i campi presenti nella richiesta.

actions/products.js
NEWACTION('Products/query', {
	name: 'List products',
	query: 'page:Number, search:String',
	output: 'items:[id:UID, name:String, price:Number], page:Number',
	action: function($) {
		var page = $.query.page || 1;
		var builder = NOSQL('products').find().sort('name').take(10).skip((page - 1) * 10);
		if ($.query.search)
			builder.search('name', $.query.search);
		builder.callback((err, items) => $.callback({ items: items, page: page }));
	}
});

NEWACTION('Products/read', {
	name: 'Read a product',
	params: '*id:UID',
	output: 'id:UID, name:String, price:Number',
	action: function($) {
		NOSQL('products').read().where('id', $.params.id).callback(function(err, item) {
			if (item)
				$.callback(item);
			else
				$.invalid(404);
		});
	}
});

NEWACTION('Products/insert', {
	name: 'Create a product',
	input: '*name:String, *price:Number',
	action: function($, model) {
		model.id = UID();
		NOSQL('products').insert(model).callback(() => $.callback({ id: model.id }));
	}
});

NEWACTION('Products/update', {
	name: 'Replace a product',
	params: '*id:UID',
	input: '*name:String, *price:Number',
	action: function($, model) {
		NOSQL('products').update(model).where('id', $.params.id).callback(function(err, count) {
			if (count)
				$.success();
			else
				$.invalid(404);
		});
	}
});

NEWACTION('Products/patch', {
	name: 'Change some fields of a product',
	partial: true,
	params: '*id:UID',
	input: 'name:String, price:Number',
	action: function($, model) {
		NOSQL('products').update(model).where('id', $.params.id).callback(function(err, count) {
			if (count)
				$.success();
			else
				$.invalid(404);
		});
	}
});

NEWACTION('Products/remove', {
	name: 'Remove a product',
	params: '*id:UID',
	action: function($) {
		NOSQL('products').remove().where('id', $.params.id).callback(function(err, count) {
			if (count)
				$.success();
			else
				$.invalid(404);
		});
	}
});
controllers/products.js
exports.install = function() {
	ROUTE('GET    /products/            --> *Products/query');
	ROUTE('GET    /products/{id}/       --> *Products/read');
	ROUTE('POST   /products/            --> *Products/insert');
	ROUTE('PUT    /products/{id}/       --> *Products/update');
	ROUTE('PATCH  /products/{id}/       --> *Products/patch');
	ROUTE('DELETE /products/{id}/       --> *Products/remove');
};