Services¶
APIs are defined via Service
s. Put simply, a
Service
is an HTTP server that exposes a JSON REST API and
which is defined as a tree of Endpoint
s.
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 Service
s 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.