API orchestration module (AOM)
1 - AOM provides following method to be called from within the request handling chain of an Express server:
orchestrateApis(opts, callback, objs)
- This passes control to a
main
method in an application-specific orchestration module, or returns an error to thecallback
method if no application-specific orchestration module can be found. - Argument
opts
is cloned and then passed into themain
method. It is expected to contain:appOrchModule
: a resolvable path to an application-specific orchestration moduleapiOptions
: a json configuration object containingrequest
options for each API callreqParams
: an object with request params (a reference to Express'req.params
)reqQuery
: an object with querystring values (a reference to Express'req.query
)contextProp
: the name of a context property, to be used as container for derived API response values (seemergeResultWithDerived
below)
- Argument
callback
is expected to be a callback function which will be called when the orchestration finishes. - Argument
objs
is optional, it can be used to pass objects that should not be cloned, like class instances.
- This passes control to a
2 - AOM provides following methods for application's orchestration code:
-
replaceUriVars(apiOptions, uriVars)
- takes a uri (
apiOptions.uri
) with placeholder variables and replaces those placeholders with actual values. - Argument
apiOptions
: options to be passed in to the request module; the method will modify theuri
property of this object - Argument
uriVars
: an object containing all uri placeholders and their values
- takes a uri (
-
getApiData(apiOptions, uriVars, callback)
- makes an API call, using the
request
module and returns a callback with(err, result)
signature, and standardizes error handling/messaging. - Argument
apiOptions
: options to be passed in to the request module: it should contain at least auri
property which may have variable placeholders enclosed in curly braces ({myVar}
), and may contain optionalheaders
that will be passed to the API request - Argument
uriVars
: object with replacement values for the uri placeholders
- makes an API call, using the
-
getErrorResponse(err, body)
- returns a standardized error response object (proper response status still needs to be handled by the server)
- Argument
err
: an error ID or short string - Argument
body
: the full error dump, could be stack trace or error response from API
-
lodash
- a wrapper for all lodash methods
3 - AOM makes an instance of a flow
object available to the application-specific orchestration module. This flow
object provides:
-
a facade to a select subset of methods that are derived from the vasync module:
parallel(ArrayOfFunctions, callback)
: invoke N functions in parallel (and merge the results). Each function should expect arguments(flow, callback)
.waterfall(ArrayOfFunctions, callback)
: invoke N functions in series, propagating results between stages. The first function in the array should expect arguments(flow, callback)
. All subsequent functions should expect arguments(flow, dependency, callback)
, wheredependency
contains the data results of the previous functions within the chain.
-
access to the
apiOptions
,envVars
,reqParams
andreqQuery
properties. -
a method
mergeResultWithDerived(result, derived)
- merges a result object with a "derived" object; the derived object should contain any data that is derived/added by the orchestration logic to enhance API data. The derived data is placed in the contextProp namespace (='gc', the client-side global context)
Sample application-specific pseudo-code:
var apiUtils = ; // the main function is called from the server{ // we need to get data for events and artist, these calls can be made in // 'parallel' since there is no dependency flow;} // all functions that are called by the 'flow' methods have access to the// 'apiOptions', 'reqParams' and 'reqQuery' objects (which were passed into 'main'){ var uriVars = host: flowapiOptionsparamshost performerId: flowreqParamsparam start: flowapiOptionsupcomingEventsparamsstart rows: flowapiOptionsupcomingEventsparamsrows ; apiUtils;} // to get the artist info, we need to make two API calls: the URI for the second// call needs to be constructed with data from the first call, hence there is a// dependency between the two, which is handled by 'waterfall'.{ flow;} { var uriVars = host: flowapiOptionsparamshost performerId: flowreqParamsparam ; return apiUtils;} // this method is called from within a waterfall and gets the result// from the previous call through the 'dependency' argument{ var uriVars = extcatalogapi_host: flowapiOptionsparamsextcatalogapi_host artistNames: ; return apiUtils;} // a helper function that parses result data{ var performerName = ""; // custom logic to extract a performer name from the result return performerName;} // a helper function that derives an image path{ var imgPath = ""; // custom logic to extract an image path from the result return imgPath;}
Sample SPA config for a QA environment:
General app.json
:
Environment-specific app_*.json
, for example app_development.json
: