module:api
- Description:
HTTP API to the server from the clients, this module implements the basic HTTP(S) API functionality with some common features. The API module incorporates the Express server which is exposed as api.app object, the server spawns Web workers to perform actual operations, monitors the worker processes if they die and restart them automatically.
How many processes to spawn can be configured via -server-max-workers config parameter.
When an HTTP request arrives it goes over Express middleware, but before processing any registered routes there are several steps performed:
- the req object which is by convention is a Request object, assigned with common backend properties to be used later:
- user - an empty object which will be filled after by signature verification method, if successful, properties from the bk_user table will be set
- options - an object with internal state and control parameters. Every request always has an options object attached very
early with some properties always present:
- ip - cached IP address
- host - cached host header from the request
- path - parsed request url path
- apath - an array with the path split by /
- secure - if the request is encrypted, like https
- appTimezone - milliseconds offset from the UTC provided in the header by the app
- access verification, can the request be satisfied without proper signature, i.e. is this a public request
- autherization, check the signature and other global or user specific checks
- when a API route found by the request url, it is called as any regular Express middlware
- if there are registered pre processing callback they will be called during access or autherization phases
- if inside the route a response was returned using api.sendJSON method, registered post process callbacks will be called for such response
Every request has the trace property, either fake or X-Ray depending on the config, see metrics for usage
Health enquiry
When running with AWS load balancer there should be a url that a load balancer polls all the time and this must be very quick and lightweight request. For this purpose there is an API endpoint /ping that just responds with status 200. It is open by default in the default api-allow-path config parameter.
- the req object which is by convention is a Request object, assigned with common backend properties to be used later:
- Source:
Members
(inner) args :Array.<ConfigOptions>
(inner) bind :string
(inner) port :int
Methods
(static) checkProxy() → {string}
- Description:
Web proxy: checkProxy("web", req, res) WS proxy: checkProxy("ws", req, socket, head)
- Source:
Returns:
| Type | Description |
|---|---|
| string |
|
(static) checkRateLimits(req, options, callback)
- Description:
Perform rate limiting by specified property, if not given no limiting is done.
- Source:
Parameters:
| Name | Type | Description | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
req |
object | Express Request |
||||||||||||||||||||||||||||||||||||||||
options |
object |
Properties
|
||||||||||||||||||||||||||||||||||||||||
callback |
function | as function(err, info) where info is from module:cache.limiter |
Examples
api.checkRateLimits(req, { type: "ip", rate: 100, interval: 60000 }, (err, info) => {
if (err) return api.sendReply(err);
...
});
More endpoint config examples
api-rlimits-map-/pub/settings=rate:10,interval:1000,delay:250
api-rlimits-map-GET/passkey/login=rate:3,interval:1000,delay:250
api-rlimits-map-/login=rate:3,interval:30000,delay:1000,multiplier:1.5,queue:unique
api-rlimits-map-/checkin*=rate:5,interval:30000
(static) checkRedirectPlaceholders(req, pathname) → {string}
Parameters:
| Name | Type | Description |
|---|---|---|
req |
object | Express Request |
pathname |
string | redirect path, it may contain placeholders in the form: @name@:
|
Returns:
| Type | Description |
|---|---|
| string |
possibly new path |
(static) cleanupHeaders()
- Description:
For now just convert cookies into an object so logger can process
- Source:
(static) cleanupResult(req, table, data) → {object|Array.<object>}
- Description:
Process records and keep only public properties as defined in the table columns. This method is supposed to be used in the post process callbacks after all records have been processes and are ready to be returned to the client, the last step would be to cleanup all non public columns if necessary. See the
apiobject in DbTableColumn for all supported conditions.
- Source:
Parameters:
| Name | Type | Description | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
req |
object | Express HTTP incoming request Properties
|
||||||||||||||||
table |
string | Array.<string> | can be a single table name or a list of table names which combined public columns need to be kept in the rows. |
||||||||||||||||
data |
object | Array.<object> |
Returns:
| Type | Description |
|---|---|
| object | Array.<object> |
cleaned records |
(static) createWebServer(port, bindopt, restartopt, sslopt, timeoutopt, keepAliveTimeoutopt, requestTimeoutopt, maxRequestsPerSocketopt, maxHeaderSizeopt, reusePortopt, nameopt)
- Description:
Create a Web server with options and request handler, returns a server object.
Options can have the following properties:
- Source:
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
port |
int | port number is required |
|
bind |
string |
<optional> |
address to bind |
restart |
string |
<optional> |
name of the processes to restart on address in use error, usually "web" |
ssl |
objext |
<optional> |
an object with SSL options for TLS createServer call |
timeout |
int |
<optional> |
number of milliseconds for the request timeout |
keepAliveTimeout |
int |
<optional> |
number of milliseconds to keep the HTTP connecton alive |
requestTimeout |
int |
<optional> |
number of milliseconds to receive the entire request from the client |
maxRequestsPerSocket |
int |
<optional> |
number of requests a socket can handle before closing keep alive connection |
maxHeaderSize |
int |
<optional> |
maximum length of request headers in bytes |
reusePort |
boolean |
<optional> |
allows multiple sockets on the same host to bind to the same port |
name |
string |
<optional> |
server name to be assigned |
(static) getResultPage(req, rows, info) → {object}
- Description:
Return an object to be returned to the client as a page of result data with possibly next token if present in the info. This result object can be used for pagination responses.
- Source:
Parameters:
| Name | Type | Attributes | Description | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
req |
object | Express Request object Properties
|
|||||||||
rows |
object | Array.<object> | ||||||||||
info |
object |
Properties
|
|||||||||
req.options.total |
number |
<optional> |
total results if available (Elasticsearch) |
Returns:
| Type | Description |
|---|---|
| object |
with properties { count, data, next_token, total } |
(static) getTokenSecret(req) → {string}
- Description:
Return a secret to be used for enrypting tokens, it uses the user property if configured or the global API token to be used to encrypt data and pass it to the clients.
-api-query-token-secretcan be configured and if a column in thebk_userwith such name exists it is used as a secret, otherwise theapi.queryTokenSecretis used as a secret.
- Source:
Parameters:
| Name | Type | Description |
|---|---|---|
req |
object | Express Request object |
Returns:
| Type | Description |
|---|---|
| string |
(static) handleBody()
- Description:
Parse incoming query parameters in the request body, this is default middleware called early before authenticatoion. Only methods in
-api-body-methodsprocessed, defaults are POST/PUT/PATCH. Store parsed parameters in thereq.body.
- Source:
(static) handleCleanup()
- Description:
Call registered cleanup hooks and clear the request explicitly
- Source:
(static) handleMetrics()
(static) handleMultipart(req, res, next)
- Description:
Parse multipart forms for uploaded files, this must be called explicitly by the endpoints that need uploads. The api module handles uploads automatically for configured paths via
-api-body-multipartconfig parameter.
- Source:
Parameters:
| Name | Type | Description |
|---|---|---|
req |
object | Express Request |
res |
object | Express Response |
next |
function |
Example
api.app.post("/upload", api.handleMultipart, (req, res, next) => {
if (req.files.file) ....
})
// Another global way to handle uploads for many endpoints is to call it for all known paths at once before the actual upload handlers.
api.app.post(/^\/upload\//, api.handleMultipart, (req, res, next) => (next("route")));
...
api.app.post("/upload/icon", (req, res, next) => {
...
api.app.post("/upload/icon", (req, res, next) => {
(static) init()
- Description:
Initialize API layer, this must be called before the
apimodule can be used but it is called by the server module automatically soapi.initis rearely need to called directly, only for new server implementation or if using in the shell for testing.During the init sequence, this function calls
configureMiddlewareandconfigureWebmethods of all modules.The api uses its own request parser that places query parameters into
req.queryorreq.bodydepending on the method.For GET method,
req.querycontains all url-encoded parameters, for POST methodreq.bodycontains url-encoded parameters or parsed JSON payload or multipart payload.
- Source:
(static) prepareOptions()
- Description:
Parse or re-parse special headers about app version, language and timezone, it is called early to parse headers first and then right after the query parameters are available, query values have higher priority than headers.
- Source:
(static) prepareRequest()
- Description:
Prepare request options that the API routes will merge with, can be used by pre process hooks, initialize required properties for subsequent use
- Source:
(static) registerPreHeaders(req, callback)
- Description:
Register a callback to be called just before HTTP headers are flushed, the callback may update response headers
- Source:
Parameters:
| Name | Type | Description |
|---|---|---|
req |
object | Express Request |
callback |
function | is a function(req, res, statusCode) |
(static) registerRateLimits(name, options)
- Description:
Register access rate limit for a given name, all other rate limit properties will be applied as described in the module:api.checkRateLimits
- Source:
Parameters:
| Name | Type | Description | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
name |
string | path or reserved rate type |
|||||||||||||||
options |
object |
Properties
|
(static) replacePath(req, path)
- Description:
Replace current request path including updating request options. It is used in routing and vhosting.
- Source:
Parameters:
| Name | Type | Description |
|---|---|---|
req |
object | Express Request |
path |
stream | new request path |
(static) sendFile(req, file, redirectopt)
- Description:
Send file back to the client or return 404 status
- Source:
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
req |
object | Express Request |
|
file |
string | file path |
|
redirect |
boolean |
<optional> |
redirect url in case of error instead of returning 404 |
(static) sendFormatted()
- Description:
Send result back formatting according to the options properties:
- format - json, csv, xml, JSON is default
- separator - a separator to use for CSV and other formats
- Source:
(static) sendJSON(req, erropt, dataopt)
- Description:
Send result back with possibly executing post-process callback, this is used by all API handlers to allow custom post processing in the apps. If err is not null the error message is returned immediately with module:api.sendReply.
if
req.options.cleanupis defined it uses module:api.cleanupResult to remove not allowed properties according to the given table rules.
- Source:
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
req |
object | Express Request object |
|
options.cleanup |
string | Array.<string> |
<optional> |
a table or list of tables to use for cleaning records before returning, see module:api.cleanupResult |
err |
object | Error |
<optional> |
error object |
data |
object |
<optional> |
data to send back as JSON |
(static) sendReply(res, textopt)
- Description:
Send formatted JSON reply to an API client, calls module:api.sendStatus after formatting the parameters.
- Source:
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
res |
object | Express Response |
|
|
object | string | Error | number | different scenarios by type:
|
|
text |
string |
<optional> |
message to return |
Example
api.sendReply(res, 400, "invalid input")
api.sendReply(res, "server is not available")
(static) sendStatus(res, options)
- Description:
Return reply to the client using the options object, it contains the following properties: i18n Note:
The API server attaches fake i18n functions
req.__andres.__which are used automatically for themessageproperty before sending the response.With real i18n module these can/will be replaced performing actual translation without using
i18n.__method for messages explicitely in the application code forsendStatusorsendReplymethods.Replies can be delayed per status via
api.delaysif configured, to override any dalays setreq.options.sendDelayto nonzero value, negative equals no delay
- Source:
Parameters:
| Name | Type | Description | |||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
res |
object | Express Response |
|||||||||||||||||||||||||
options |
object |
Properties
|
(static) shutdown()
- Description:
Gracefully close all connections, call the callback after that
- Source:
(static) startMetrics()
- Description:
This is supposed to be called at the beginning of request processing to start metrics and install the handler which will be called at the end to finalize the metrics and call the cleanup handlers.
- Source:
(static) toParams(req, schema, optionsopt) → {object|string}
- Description:
Parse body/query parameters according to the
schemaby usinglib.toParams, uses the req.body if present or req.query.
- Source:
Parameters:
| Name | Type | Attributes | Description | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
req |
object | Express request |
|||||||||||||
schema |
module:lib.ParamsOptions | schema object |
|||||||||||||
options |
object |
<optional> |
Properties
|
Returns:
| Type | Description |
|---|---|
| object | string |
|
Example
var query = api.toParams(req, { q: { required: 1 } }, { null: 1 });
if (typeof query == "string") return api.sendReply(req, 400, query)