Eine vollständige REST-Ressource mit Actions bauen
Eine REST-Ressource besteht aus sechs Operationen: Liste (query), read, insert, update (ersetzen), patch (einige Felder ändern) und remove. In Total.js ist jede davon eine Action mit eigener Validierung, sodass die Routentabelle eine schlichte Zuordnung von URL zu Action bleibt. params validiert die ID der URL, query die Filter der Liste, input den Body. Innerhalb einer Action sind $.params, $.query und der validierte Body (zweites Argument von action) bereits bereinigte Werte.
Einen fehlenden Datensatz meldest du mit $.invalid(404): Es antwortet mit dem Statuscode und einem JSON-Fehler, bei jeder Action gleich. $.success() antwortet mit { "success": true } und $.callback(value) mit einem Wert, der zusätzlich durch das output der Action gefiltert wird. UID() erzeugt die ID eines neuen Datensatzes.
patch braucht partial: true. Ohne diese Option wird ein nicht gesendetes Feld trotzdem mit dem Standardwert seines Typs gefüllt ('' bei einem String), und update() würde den gespeicherten Wert mit diesem leeren Text überschreiben. Mit partial: true erreichen nur die Felder, die in der Anfrage vorhanden sind, die Action.
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);
});
}
});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');
};