Services¶
APIs are defined via Services. Put simply, a
Service is an HTTP server that exposes a JSON REST API and
which is defined as a tree of Endpoints.
Services and Endpoints¶
All Service definitions follow the same general structure:
1 2 3 4 5 6 7 8 9 10 11 12 13 | var carbon = require('carbon-io')
var o = carbon.atom.o(module)
var __ = carbon.fibers.__(module)
__(function() {
module.exports = o.main({
_type: carbon.carbond.Service,
port: 8888,
endpoints: {
// Endpoint definitions go here
}
})
})
|
Here is an example of a simple Service that runs on port
8888 and that defines a single Endpoint at the path
/hello which a defines a single get operation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | var carbon = require('carbon-io')
var o = carbon.atom.o(module)
var __ = carbon.fibers.__(module)
__(function() {
module.exports = o.main({
_type: carbon.carbond.Service,
port: 8888,
endpoints: {
hello: o({
_type: carbon.carbond.Endpoint,
get: function(req) {
return { msg: "Hello World!" }
}
})
}
})
})
|
Service middleware¶
You can register Express-style middleware for your service via the
middleware property on your
Service object:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | var carbon = require('carbon-io')
var o = carbon.atom.o(module)
var __ = carbon.fibers.__(module)
__(function() {
module.exports = o.main({
_type: carbon.carbond.Service,
port: 8888,
middleware: [
function(req, res, next) {
console.log('This is called on every request')
next()
}
],
endpoints: {
// Endpoint definitions go here
}
})
})
|
Running Services from the command line¶
In most cases you will want to start and stop your Service from
the command line.
This can be done by ensuring the value of o you are using to
define your Service is the main version
of the library, as shown below on line 6:
1 2 3 4 5 6 7 8 9 10 11 12 13 | var carbon = require('carbon-io')
var o = carbon.atom.o(module)
var __ = carbon.fibers.__(module)
__(function() {
module.exports = o.main({
_type: carbon.carbond.Service,
port: 8888,
endpoints: {
// Endpoint definitions go here
}
})
})
|
You can then start your Service like this:
% node <path-to-your-app>/lib/HelloService.js
[Mon Feb 09 2015 21:56:41 GMT-0800 (PST)] INFO: Service starting...
[Mon Feb 09 2015 21:56:41 GMT-0800 (PST)] INFO: Service listening on port 8888
[Mon Feb 09 2015 21:56:41 GMT-0800 (PST)] INFO: Service started
You can use -h or --help to get command help from your
Service:
Usage: node <path-to-your-app>/lib/HelloService.js [command] [options]
command
start-server start the api server (default)
gen-static-docs generate docs for the api
Options:
-v VERBOSITY, --verbosity VERBOSITY verbosity level (trace | debug | info | warn | error | fatal)
Environment variables:
<none>
You can see that there are two sub-commands. One for starting the server and
another for generating documentation for your Service.
The default sub-command is start-server, and will be run if you omit a
sub-command (e.g. $> node <path-to-your-app>/MyService):
Usage: node <path-to-your-app>/lib/HelloService.js start-server [options]
Options:
-v VERBOSITY, --verbosity VERBOSITY verbosity level (trace | debug | info | warn | error | fatal)
-p PORT, --port PORT port
-n HOSTNAME, --hostname HOSTNAME the hostname to bind [0.0.0.0]
-d DB_URI, --dbUri DB_URI MongoDB connection string
--cluster use node cluster
--num-cluster-workers NUM fork NUM cluster nodes (default is to fork a worker for each CPU) [0]
--exit-on-cluster-worker-exit if this flag is set, the master will exit if a work dies, otherwise a warning will be logged
--swagger mount swagger endpoints
--enable-busy-limiter send 503 responses when the node process becomes too "busy"
--fiber-pool-size SIZE set the fiber pool size [120]
start the api server (default)
Environment variables:
<none>
Embedding Services into larger applications (advanced use)¶
While you will usually run your Services via the command
line as a top-level application, Service objects can also
be used as a library (although it is not common).
By using the start and
stop methods, you can manage the
Service lifecyle manually.
These methods have both an asynchronous and a synchronous interface:
Asynchronous example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | var carbon = require('carbon-io')
var o = carbon.atom.o(module)
var myService = o({ // IMPORTANT: do not use "o.main" here
_type: carbon.carbond.Service,
port: 8888,
endpoints: {
hello: o({
_type: carbon.carbond.Endpoint,
get: function(req) {
return { msg: 'Hello World!' }
}
})
}
})
function startService(done) {
myService.start({}, function(err) {
if (err) {
myService.logError('Error starting service ' + err)
done(err)
} else {
myService.logInfo('Service started')
//
// Do stuff...
//
myService.stop(function(err) {
myService.logInfo('Service stopped')
done(err)
})
}
})
}
if (module === require.main) {
startService(function(err) {
process.exit(err ? 1 : 0)
})
}
|
Synchronous example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | var carbon = require('carbon-io')
var __ = carbon.fibers.__(module)
var o = carbon.atom.o(module)
var myService = o({ // IMPORTANT: do not use "o.main" here
_type: carbon.carbond.Service,
port: 8888,
endpoints: {
hello: o({
_type: carbon.carbond.Endpoint,
get: function(req) {
return { msg: "Hello World!" }
}
})
}
})
function startService() {
try {
myService.start()
myService.logInfo('Service started')
//
// Do stuff...
//
myService.stop()
myService.logInfo('Service stopped')
} catch (e) {
myService.logError("Error starting service " + err)
return 1
}
return 0
}
if (module === require.main) {
__(function() {
process.exit(startService())
})
}
|
Important note: you should not find yourself starting and stopping services like
this (by manually calling start and
stop) frequently. In most use-cases you will simply
use the command line invocation described in the previous section.