Petite is a microservices framework designed to power a single RESTful JSON microservice on a single port. Petite services are presumed to be running behind an external router/reverse-proxy (in their own container, but as part of a larger set of API services). As such, each service only processes a single route, and allows you to define a single controller for each HTTP method accessible on that route. Petite has zero runtime dependencies and works on Node >= 4.0. Petite is developed and maintained by Good Uncle.
npm install petite
var petite = require('petite');
To require a certain url pattern for incoming requests, pass a regEx pattern (as a string) to petite.requireUrl(). To disallow certain url patterns, pass a regEx pattern (as a string) to petite.disallowUrl().
petite.requireUrl('myservice')
petite.disallowUrl('myservice/');
To require certain headers for incoming requests, pass a key and a value to petite.requireHeader(). Keys are matched exactly. Values can be set as an regEx pattern (passed as a string).
petite.requireHeader('accept','application/json');
petite.requireHeader('client-id','.+');
Pass an http method and the name of your controller function to petite.addController(). See "Setting Up Your Controllers" below, for more details on how to define your controllers.
petite.addController('POST', myPostController);
petite.addController('GET', myGetController);
petite.addController('PUT', myPutController);
petite.addController('DELETE', myDeleteController);
Passing a key and value to petite.setConfig() will define a key for the default configuration.
petite.setConfig('key','value');
Passing a key, value, and an environment-name to petite.setConfig() will define a key for the environment named.
petite.setConfig('key','value','environmentName');
petite.setConfig('key','value','someOtherEnvironentName');
Note: Each environment inherits all the default config variables, which you can then override on a case by case basis. Also, there are 4 predefined variables that all environments inherit (including the default environment). These can be overriden as needed.
- port: 3000 (Which port the service should listen on)
- log : true (Should the service log events and message to the console?)
- debug : false (Should the service throw exceptions when they are encountered?)
- cors : false (Should the service support CORS?) If set to true, all OPTIONS requests are returned with a 200, and the following headers are sent with all responses (in addition to the Content-Type : "application/json" header that is sent regardless):
- Access-Control-Allow-Origin : "*"
- Access-Control-Allow-Methods : "POST, GET, PUT, DELETE, OPTIONS"
- Access-Control-Allow-Headers : "content-type, client-id, accept, accept-encoding, x-api-token"
See the "Accessing config data" section below for more details on how environment-specific configuration works.
The petite.start() function takes no arguments.
petite.start();
This is what happens when a request comes in to your Petite microservice.
The requested uri is checked against the required and disallowed uris you set with the requireUrl() and disallowUrl() functions. A 404 is returned if this check fails.
The headers sent with the request are checked against the required headers you define with the requireHeader() function. A 406 is returned if this check fails.
With the addController() function, you define which controller should receive the request data for each http method (POST, GET, PUT, DELETE, etc). If a request is received via a method that has no matching controller (OPTIONS or HEAD for example), a 405 is returned. If there is a matching controller for that method, that controller is passed a single data object and a callback.
Your controllers should be normal functions that accept two parameters: a data object, and a callback.
The data object contains all the request data you should need to process the request.
{
'path' : 'the/requested/path',
'pathArray' :['the','requested','path'],
'params' : {'foo' : 'bar'},
'payload' : {'fizz' : 'buzz'},
'headers' : {'accept-encoding' : 'gzip'},
'method' : 'post'
}
- data.path: The requested path received by the service, after the leading and trailing slashes have been trimmed. If the root was requested, the path will be null.
- data.pathArray: An array containing the data.path after is has been split/exploded by slashes. If the data.path contained no slashes, the array will contain one string. If the data.path was null, the array will be empty.
- data.params: An object containing key-value pairs of the url parameters sent with the request (from the request string). If no params were sent, data.params will be an empty object.
- data.payload: An object containing the payload sent. If the payload was not included or was not valid JSON, data.payload will be an empty object.
- data.headers: An object containg key-value pairs of the headers sent with the request. All headers and header-values are expressed in lowercase. If no headers are sent data.headers will be an empty object.
- data.method: A lowercase string of the http method of the request. If the method cannot be determined, data.method will be null.
The current config data that Petite is running under can be accessed at petite.config.
The petite.setConfig() function (detailed above) allows you to set default or environment-specific configuration variables. When your node application is started, Petite will check the NODE_ENV variable for an environment name. If you have set configuration variables for that environment, then petite.config will inherit that environment's configuration. If no configuration has been set for that environment, then the default configuration object will be used instead.
After processing the data passed to it, your controller should callback two things: an HTTP status code (a 3 digit number), and (optionally) a payload object. The status code and payload that your controllers call back will be returned by the microservice. If your controller throws an exception, a 500 error will be returned by the service.
callback(200, {'foo':'bar'});
var myPostController = function(data, callback){
// Get the payload data
var requestPayload = data.payload;
// Get the config data for this environment
var configData = petite.config;
// Throw an error if needed (which will make the microservice return a 500)
if(typeof(configData.foo) == 'undefined'){
throw('Foo was not defined in this environment');
} else {
// Return a status code and a payload
var responsePayload = {'foo':'bar'};
var statusCode = 200;
callback(statusCode, responsePayload);
}
});
Petite services are designed to run in standalone containers, behind an external reverse-proxy or router (which sends requests to the container only when requests are received with matching paths). Dockerizing a Petite service is as simple as including a Dockerfile like so:
# Use the Node 4.0 docker image
FROM node:4-onbuild
# Expose ports needed by the environments
EXPOSE 80
EXPOSE 443
EXPOSE 3000
The MIT License (MIT)
Copyright (c) 2016 Rosco & Benedetto Co.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.