Quick API server for testing
When you need an API server for testing there's Total.js framework to get you up and running in minutes. If You want to know how then keep reading.
- first of all let's create a folder and install Total.js
$ mkdir apitest
$ cd apitest
$ npm install total.js
- now let's create index.js which will be the only file we need:
- open the file in your favorite Sublime Text editor :)
Server
First thing we do is setup a server using framework.http:
require('total.js').http('release'); // default port 8000
// require('total.js').http('release', {port: 10000});
The above code can be used as a static file server. If You create a public
folder then whatever you place in there will be accessible. e.g. ./public/favicon.ico => localhost:8000/favicon.ico
.
Schema
Next we setup a schema and some properties using SchemaBuilder.
NEWSCHEMA('Product').make(function(schema) {
schema.define('name', String, true);
schema.define('price', Number, true);
schema.define('description', String);
// Query products
schema.setQuery(function(error, options, callback) {
// pagination
options.page = U.parseInt(options.page) - 1;
options.max = U.parseInt(options.max, 20);
// if page not specified set it to 0
if (options.page < 0)
options.page = 0;
// number of items to return
var take = U.parseInt(options.max);
// number of items to skip
var skip = U.parseInt(options.page * options.max);
// NOSQL is total.js embedded database
// https://docs.totaljs.com/latest/en.html#api~Database
var filter = NOSQL('products').find();
filter.take(take);
filter.skip(skip);
if(options.sort) filter.sort(options.sort);
filter.callback(function(err, docs, count) {
// let's create object which will be returned
var data = {};
data.count = count;
data.items = docs;
data.limit = options.max;
data.pages = Math.ceil(data.count / options.max) || 1;
data.page = options.page + 1;
callback(data);
});
});
// Get single product by id
schema.setGet(function(error, model, id, callback) {
NOSQL('products')
.one()
.where('id', id)
.callback(function(err, product){
callback({success: !!product, data: product});
});
});
// Save the product into the database
schema.setSave(function(error, model, options, callback) {
// if there's no id then it's an insert otherwise update
var isNew = model.id ? false : true;
// create id if it's new
if(isNew) model.id = UID(); //UID returns string such as 16042321110001yfg
NOSQL('products')
.upsert(model) // update or insert
.where('id', model.id)
.callback(function() {
callback({success: true, id: model.id});
});
});
// Remove a specific product
schema.setRemove(function(error, id, callback) {
NOSQL('products')
.remove()
.where('id', id)
.callback(function(){
callback({success: true});
});
});
});
Routes
Now it's time to create some routes using F.route. In each route we use *Product
flag which tells the framework we want to use the schema methods in a controller.
// URL Handler Flags Method
F.route('/api/products', query, ['*Product']); // GET (default)
F.route('/api/products/{id}', get, ['*Product']); // GET (default)
F.route('/api/products', save, ['*Product', 'post']); // POST
F.route('/api/products/{id}', remove, ['*Product', 'delete']);// DELETE
Controllers
Since we've specified the *Product
flag we can use schema methods such as $get, $query, $save, etc.
.
function query() {
// `this` is an instance of Controller
// https://docs.totaljs.com/latest/en.html#api~FrameworkController
var self = this;
// $query is Schema method that we defined using `schema.setQuery(...)`
self.$query(self.query, self.callback());
// instead of self.callback you can supply your own callback function
// self.$query(self.query, function(err, result){
// self.json(result);
// });
}
function get(id) {
// the id is parsed by framework from url `/api/products/{id}`
var self = this;
// $get is Schema method that we defined using `schema.setGet(...)`
this.$get(id, self.callback());
}
function save() {
var self = this;
// $save is Schema method that we defined using `schema.setSave(...)`
// the $save method is available on this.body for POST request
this.body.$save(self.callback());
// another way to use it is
// this.$save(this.body, self.callback());
}
function remove(id) {
var self = this;
// $remove is Schema method that we defined using `schema.setRemove(...)`
this.$remove(id, self.callback());
}
Logging requests
Let's add logging for each request so we know what's going on:
F.on('request', function(req, res){
console.log(`[${req.method}] ${req.url}`);
// outputs e.g. `[GET] /api/products`
});
Find the gist here index.js.
If you want it to work really quickly you can use recently added functionality NOSQL inmemory
. Add it just bellow require('total.js').http('release');
.
This will keep all documents from products
collection in memory for quicker access.
Links: