const swatch = require('swatchjs');
const model = swatch({
add: (a, b) => a + b,
sub: (a, b) => a - b,
);
SwatchJS is a javascript framework for easily creating and exposing APIs as methods.
SwatchJS allows your API functions to be written in the same way that any other function is written: they take parameters, have a return value, and throw exceptions. They are easy to write and test. You can write your API independent of a transport layer. You don't have to worry about status codes, routes, request context, query parameters, or any of that code that slows you down. It's less code to write and test. Next, you can choose how to expose your API, using one of pre-existing adapters, or by writing a new one. These adapters range from simple GET calls over HTTP, to SOAP, to JSON-RPC, to Protobufs, etc.
To install, simply run:
npm install swatchjs
The following creates a simple API which takes 2 parameters (a
and b
) and
returns their sum (add
method) or difference (sub
method).
const swatch = require('swatchjs');
const model = swatch({
add: (a, b) => a + b,
sub: (a, b) => a - b,
});
That's it. You are in business. All that is left is to expose the model, usually through one of the adapters. It's quick and easy. No need to write unnecessary code for the application or transport layer. KISS.
swatch
functionconst swatch = require('swatchjs');
const model = swatch({
// api
});
Loading this library will result in a function (swatch in the example above) which when called will produce a model for the API. This model can then be passed to adapters to expose that API. See Exposing the API below for more details.
This function takes an object which describes the API, and it looks like this:
{
"service.api1": myApiFn1,
"service.api2": myApiFn2,
// ...
}
Each methodName
is the name for the API you want to expose. The convention is to
group the APIs by functionality area (often by microservices), with camelCase names separated
by dots (e.g.:users.create
, users.delete
, users.options.add
,
users.options.list
, users.options.setDefault
).
Each method name is associated with a handler. The handler can be the function which will handle the API method call, or it can be an object that provides a little more flexibility in describing the function.
The following errors will be generated when the API is declared:
Error | Description |
---|---|
invalid_arg_list |
One or more of the provided method args lists did not match the handler
function.
|
The easiest way to expose an API method is to just associate the method name with its function. When exposed, each of the parameters in the function will be arguments in the method.
function createUser(username, password, name) {
// ...
}
const model = swatch({
"users.create": createUser,
});
In the example above, when invoking users.create
, the user would pass in three arguments:
username
, password
, and name
. The framework automatically
matches the arguments passed in by the user to the function arguments.
Alternatively, you can have more control over the behavior of each API method, as illustrated below:
function createUser(username, password, name) {
// ...
}
function middlewareFn(ctx, next) {
// ...
}
const model = swatch({
"users.create": {
handler: createUser,
args: [
{
name: 'username',
parse: String,
optional: false,
},
{
name: 'password',
parse: String,
optional: false,
},
{
name: 'name',
parse: String,
optional: true,
default: 'New User',
},
],
middleware: [middlewareFn],
},
});
In this scenario, when invoking users.create
, the user would still pass in three
arguments: username
, password
, and name
. The framework
automatically matches the username
value to the first argument, the password
value to the second argument, and name
value to the third argument of the createUser
function. Additionally, the name
value is optional and will provide a default
value of 'New User'
if the argument is not present.
If the args
array is present, it must match the function in arity (i.e., the number
of arguments declared in the function must match the number of elements in the args
array).
The following properties can be set:
Property | Required? | Description |
---|---|---|
handler |
Yes | The API handler. Must be a function. |
args |
No | Function arguments. Must be an array. See below for more information. |
metadata |
No | An object with additional information about the handler (see below). |
If the args
array is present, it must match the function in arity (i.e., the number
of arguments declared in the function must match the number of elements in the args
array). Each element in the array can be either a string or an object.
If an element is an object, then the following properties are valid:
Property | Required? | Description |
---|---|---|
args[idx].name |
No | The name of the parameter as passed by caller. Defaults to the name specified in the function. |
args[idx].parse |
No | A function that will be executed on the input. Can be used to perform type coercions. If present, should return desired value, or throw. |
args[idx].validate/code> |
No | A function that will be executed on the successfully parsed/coerced input value. Should not modify or return a value, should throw if invalid. |
args[idx].optional |
No | A boolean indicating whether the argument is optional. Defaults to false. If user fails to provide a required arguments, the request will fail. |
args[idx].default |
No | A primitive type or object. If user fails to provide an optional argument, the default will be provided. |
If an element is a string "argName", then it is considered equivalent to the object { name: "argName" }
.
If the metadata
object is present, the following sub-properties can be set:
Property | Required? | Description |
---|---|---|
noAuth |
No | A boolean that indicates whether the authAdapter (if any is defined by swatchKoa or swatchExpress options) should be skipped for this particular method handler. Defaults to false . |
middleware |
No | An array of functions to run as middleware. Accepts request context and callback function as params. Throw on error to abort request handler. |
The following errors will be generated during runtime (when invoking the handler):
Error | Description |
---|---|
invalid_arg_name |
One or more of the provided arguments was not expected by the handler. |
missing_arg |
One or more of the required arguments were not provided. |