A REST API server
Our database connector will now function as a full fledged REST API server. We need only add a HTTP server to it.
HTTP servers. Feathers is currently tied into the popular HTTP server framework Express. Future versions will support multiple frameworks, starting with koa.
Working example
- Source code: examples/step/01/rest/1.js. and common/
- Run it:
node ./examples/step/01/rest/1.js
- Compare with last page's examples/step/01/db-connector/1.js: Unified | Split
Implementing a REST API server
This is our previous example with the database method calls removed, and with an Express server added.
// Example - Create REST API
const expressServerConfig = require('../common/expressServerConfig');
const expressMiddleware = require('../common/expressMiddleware');
const rest = require('feathers-rest');
const NeDB = require('nedb');
const path = require('path');
const service = require('feathers-nedb');
const app = expressServerConfig()
.configure(rest())
.configure(services)
.configure(expressMiddleware);
const server = app.listen(3030);
server.on('listening', () => console.log(`Feathers application started on port 3030`));
function services() {
this.use('/users', service({ Model: userModel() }));
}
function userModel() {
return new NeDB({
filename: path.join('examples', 'step', 'data', 'users.db'),
autoload: true
});
}
The Express server common/expressServerConfig.js is configured as follows.
const bodyParser = require('body-parser');
const compress = require('compression');
const cors = require('cors');
const path = require('path');
const feathers = require('feathers');
module.exports = () => {
const app = feathers()
.use(compress())
.options('*', cors())
.use(cors())
.use('/', feathers.static(path.join(__dirname, 'public')))
.use(bodyParser.json())
.use(bodyParser.urlencoded({ extended: true }));
return app;
};
The Express middleware common/expressMiddleware/index.js handles logging, pages not found, and general errors.
'use strict';
const handler = require('feathers-errors/handler');
const notFound = require('./not-found-handler');
const logger = require('./logger');
module.exports = function() {
const app = this;
app.use(notFound());
app.use(logger(app));
app.use(handler());
};
Boilerplate. The server configuration and middleware are standard Express. They have little to do with Feathers other than to feed REST requests to it.
Running the server
We can now make REST API calls to the server.
In the previous example we created 3 user items and then printed the user file. We can now do the same thing, but using REST, with curl commands:
printf "\nPOST Jane Doe\n"
curl -H "Content-Type: application/json" -X POST -d '{"email":"[email protected]","password":"X2y6","role":"admin"}' http://localhost:3030/users
printf "\nPOST John Doe\n"
curl -H "Content-Type: application/json" -X POST -d '{"email":"[email protected]","password":"i6He","role":"user"}' http://localhost:3030/users
printf "\nPOST Judy Doe\n"
curl -H "Content-Type: application/json" -X POST -d '{"email":"[email protected]","password":"7jHw","role":"user"}' http://localhost:3030/users
printf "\nGET all users\n"
curl -X GET http://localhost:3030/users
First, start the server by running node ./examples/step/01/rest/1.js
on one terminal.
Then run the curl commands with ./examples/step/01/rest/curl-requests.sh
on another terminal.
Results
That console displays:
feathers-guide$ ./examples/step/01/rest/curl-requests.sh
POST Jane Doe
{"email":"[email protected]","password":"X2y6","role":"admin","_id":"sbkXV7LVkMhx1NyY"}
POST John Doe
{"email":"[email protected]","password":"i6He","role":"user","_id":"uKhqOp4R4hABw9oO"}
POST Judy Doe
{"email":"[email protected]","password":"7jHw","role":"user","_id":"pvcmh9X2i9VZgqWJ"}
GET all users
[
{"email":"[email protected]","password":"7jHw","role":"user","_id":"pvcmh9X2i9VZgqWJ"},
{"email":"[email protected]","password":"X2y6","role":"admin","_id":"sbkXV7LVkMhx1NyY"},
{"email":"[email protected]","password":"i6He","role":"user","_id":"uKhqOp4R4hABw9oO"}
]
Feathers. REST API calls are automatically converted into Feathers database method calls like the
users.create()
andusers.find()
methods we used in the previous example. How's that for convenience?